React 图解完整版:
链接:pan.baidu.com/s/1EfTWzqC4… 密码:8nqr
🍀ReactContext.js: createContext 创建 context
传入的参数为:
defaultValue provider提供的默认值
calculateChangedBits 自定义的 vakue 比较函数,默认情况下如果传入 provider 的 value 值没有变化则返回 0,否则返回 1073741823
定义context:
const context: ReactContext<T> = {
$$typeof: REACT_CONTEXT_TYPE,
_calculateChangedBits: calculateChangedBits,
_currentValue: defaultValue,
_currentValue2: defaultValue,
// These are circular
// 循环引用
Provider: (null: any),
Consumer: (null: any),
};
定义context.Provider:
context.Provider = {
$$typeof: REACT_PROVIDER_TYPE,
_context: context,//引用context
};
生产环境下定义context.Consumer
context.Consumer = context
🍀 context 跨组件通信原理
用于保存 Provider value 的栈
在调用 createContext 的过程中其中 valueStack 用于保存所有 context 的 provider 提供的 value,其中还包括一些 namespace 等内容。在 provider 上提供的值,任意位置的 consumer 组件以及通过 Class.contextType 赋予类组件中的 this.context 都可以通过 cursor.current 去取到最近的 provider 提供的。React 利用栈这个数据结构以及遍历 fiber 树的方式,保证了消费者能正确获取到 context.provider 的值。
react 对上述栈的封装
-
push 方法将 cursor.current 的值推到 valueStack 的栈顶,然后把当前 provider 节点的变化了的 value 值放到 cursor.current 中。
-
pop 方法则将 cursor.current 的值替换成 valueStack 栈顶的值,然后栈顶的值重置为 null,接着 index--。
react 在 renderRoot 阶段的遍历方式以及对上述栈的处理时机
- performUnitOfWork 每次都会在 completeUnitOfWork 之前调用。而在performUnitOfWork中会调用updateContextProvider,该函数会调用pushProvider将 cursor.current放到栈顶,然后新的value放到cursor.current上。
- 接着在遇到 context.consumer 的时候,会去读取这个 cursor.current 的值,给到 Consumer 的 children,也就是一个函数,接收 provider 的 value。在遇到 classComponent 的时候,同样会读取 cursor.current 的值然后赋值给组件实例的 context。
- 最后调用completeUnitOfWork的时候又会去popPrivider,pop会将栈顶的value恢复到cursor.current。所以永远取得的是最近的priovider的value。
可以结合下面的图观察一下,per里面push,com中pop。push和pop之间取得的value就是push进去的。