React中Context的变化及其背后的实现
Context在这篇文章中,我们说说Context。Context可以实现数据的跨组件传递。大多数时候,它是没有必要的,但有时,例如,如果用户设置了UI主题或区域偏好,如果从顶层向下传递到底层就有点麻烦了。最好直接使用Context来实现数据传递。OldContextAPI基本示例在说最新的API之前,我们先来回顾一下旧的ContextAPI:context.value}
}}//3.子组件添加contextTypes静态属性Child.contextTypes={value:PropTypes.string};classParentextendsReact.Component{state={value:'foo'}//1.当state或props发生变化时,会调用getChildContext函数getChildContext(){return{value:this.state.value}}render(){return(
)}}//2.给父组件添加childContextTypes静态属性Parent.childContextTypes={value:PropTypes.string};上下文中断问题对于这个API,React官方不推荐使用。对于可能出现的问题,React文档给出的介绍是:问题是如果组件提供的一个context发生变化,中间父组件的shouldComponentUpdate返回false,那么使用这个值的后代组件将不会更新。使用上下文的组件完全不受控制,因此基本上没有办法可靠地更新上下文。针对这个问题,我们来写个示例代码://1.子组件使用PureComponent>{this.context.theme}}}GrandChild.contextTypes={theme:PropTypes.string};classParentextendsReact.Component{state={theme:'red'}getChildContext(){返回{theme:这个.state.theme}}render(){return(
{this.setState({theme:'blue'})}}> )}}Parent.childContextTypes={主题:PropTypes.string};在此示例代码中,当单击红色文本时,文本不会更改为蓝色。如果我们把Child改成extendsComponent,说明可以正常修改当中间组件的shouldComponentUpdate为false时,Context的传递就会中断。PureComponent的存在是为了减少不必要的渲染,但是我们也希望Context能够正常传递。有什么办法解决吗?由于PureComponent的存在使得Context不再可更新,所以根本不应该更新它。Context不更新,GrandChild就不能更新了?当然有解决方案://1.创建一个订阅发布者,当然你也可以称之为依赖注入系统(dependencyinjectionsystem),简称DIclassTheme{constructor(value){this.value=valuethis.subscriptions=[]}setValue(value){this.value=valuethis.subscriptions.forEach(f=>f())}subscribe(f){this.subscriptions.push(f)}}classChildextendsReact.PureComponent{render(){return
}}classGrandChildextendsReact.Component{componentDidMount(){//4.GrandChild获取到store后,订阅this.context.theme.subscribe(()=>this.forceUpdate())}//5.GrandChild从存储中获取所需的值render(){return
{this.context.theme.value}
}}GrandChild.contextTypes={theme:PropTypes.object};父类扩展React。组件{构造函数(p,c){超级(p,c)//2.我们实例化一个商店(想想redux的商店)并将它存储在实例属性中this.theme=newTheme('blue')}//3.将它传递给GrandChild组件getChildContext(){return{theme:this.theme}}render(){//6.通过store发布return(
{this.theme.setValue('red')}}> )}}Parent.childContextTypes={theme:PropTypes.object};为了管理我们的主题,我们建立了一个依赖注入系统(DI),将store通过Context向下传递,这就需要使用store数据组件进行订阅,传入一个forceUpdate函数。当store发布后,每个依赖主题的组件执行forceUpdate,从而实现在不更新Context的情况下更新每个依赖组件。您可能还发现了,它有点react-redux的味道。当然,我们也可以使用Mobx来实现和简化代码。具体实现可以参考MichelWeststrate(Mobx的作者)如何安全使用Reactcontext新的ContextAPI基础示例想必大家都或多或少用过,我们直接上面的示例代码://1.CreateProviderandConsumerconst{Provider,Consumer}=React.createContext('dark');classChildextendsReact.Component{//3.Consumer组件接收一个函数作为子元素。此函数获取当前上下文值并返回一个React节点。render(){return(
)}}classParentextendsReact.组件{state={theme:'dark',};componentDidMount(){setTimeout(()=>{this.setState({theme:'light'})},2000)}render(){//2.通过Provider传值return(