Open mqyqingfeng opened 1 year ago
这里是不是不太对,如果多次更新,那就会push多次
// Provider
class Provider extends React.PureComponent {
componentDidUpdate() {
store.publish(this.props.value);
}
componentDidMount() {
store.publish(this.props.value);
}
render() {
return this.props.children;
}
}
store.subscribe(value => {
this.setState({
value
});
});
Context
本篇我们讲 Context,Context 可以实现跨组件传递数据,大部分的时候并无需要,但有的时候,比如用户设置 了 UI 主题、地区偏好,如果从顶层一层层往下传反而有些麻烦,不如直接借助 Context 实现数据传递。
老的 Context API
基础示例
在讲最新的 API 前,我们先回顾下老的 Context API:
context 中断问题
对于这个 API,React 官方并不建议使用,对于可能会出现的问题,React 文档给出的介绍为:
对于这个问题,我们写个示例代码:
在这个示例代码中,当点击文字
red
的时候,文字并不会修改为blue
,如果我们把 Child 改为extends Component
,则能正常修改这说明当中间组件的
shouldComponentUpdate
为false
时,会中断 Context 的传递。PureComponent 的存在是为了减少不必要的渲染,但我们又想 Context 能正常传递,哪有办法可以解决吗?
既然 PureComponent 的存在导致了 Context 无法再更新,那就干脆不更新了,Context 不更新,GrandChild 就无法更新吗?
解决方案
方法当然是有的:
为了管理我们的 theme ,我们建立了一个依赖注入系统(DI),并通过 Context 向下传递 store,需要用到 store 数据的组件进行订阅,传入一个 forceUpdate 函数,当 store 进行发布的时候,依赖 theme 的各个组件执行 forceUpdate,由此实现了在 Context 不更新的情况下实现了各个依赖组件的更新。
你可能也发现了,这有了一点 react-redux 的味道。
当然我们也可以借助 Mobx 来实现并简化代码,具体的实现可以参考 Michel Weststrate(Mobx 的作者) 的 How to safely use React context
新的 Context API
基础示例
想必大家都或多或少的用过,我们直接上示例代码:
当 Provider 的 value 值发生变化时,它内部的所有 consumer 组件都会重新渲染。
模拟实现
那么 createContext 是怎么实现的呢?我们先不看源码,根据前面的订阅发布器的经验,我们自己其实就可以写出一个 createContext 来,我们写一个试试:
用我们写的 createContext 替换 React.createContext 方法,你会发现,同样可以运行。
它其实跟解决老 Context API 问题的方法是一样的,只不过是做了一层封装。Consumer 组件构建的时候进行订阅,当 Provider 有更新的时候进行发布,这样就跳过了 PureComponent 的限制,实现 Consumer 组件的更新。
createContext 源码
现在我们去看看真的 createContext 源码,源码位置在
packages/react/src/ReactContext.js
,简化后的代码如下:你会发现,如同之前的文章中涉及的源码一样,React 的 createContext 就只是返回了一个数据对象,但没有关系,以后的文章中会慢慢解析实现过程。
React 系列
讲解 React 源码、React API 背后的实现机制,React 最佳实践、React 的发展与历史等,预计 50 篇左右,欢迎关注
如果喜欢或者有所启发,欢迎 star,对作者也是一种鼓励。