You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
import{REACT_PROVIDER_TYPE,REACT_CONTEXT_TYPE}from'shared/ReactSymbols';exportfunctioncreateContext(defaultValue){constcontext={$$typeof: REACT_CONTEXT_TYPE,// As a workaround to support multiple concurrent renderers, we categorize// some renderers as primary and others as secondary. We only expect// there to be two concurrent renderers at most: React Native (primary) and// Fabric (secondary); React DOM (primary) and React ART (secondary).// Secondary renderers store their context values on separate fields._currentValue: defaultValue,_currentValue2: defaultValue,// Used to track how many concurrent renderers this context currently// supports within in a single renderer. Such as parallel server rendering._threadCount: 0,// These are circularProvider: null,Consumer: null,// Add these to use same hidden class in VM as ServerContext_defaultValue: null,_globalName: null,};context.Provider={$$typeof: REACT_PROVIDER_TYPE,_context: context,};context.Consumer=context;returncontext;}
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,对作者也是一种鼓励。
The text was updated successfully, but these errors were encountered: