context原理介绍
context是React提供的一种将状态存储到顶层的机制,通过该机制可以完成简单的状态管理,比如结合useImmer/发布订阅。
但是context也有一个致命的缺点:context中存了多个数据时,某个中间组件只用了部分数据,但是context更新后,也会导致组件重刷。
原理
首先简单介绍一下context的使用:createContext创建一个context对象,然后把管理的状态放到context.Provider中,取值时通过useContext取值。 createContext源码简化后如下:
function createContext(defaultValue) {
const context = {
$$typeof: REACT_CONTEXT_TYPE,
_currentValue: defaultValue,
Provider: null,
Consumer: null,
// 省略其他属性
}
context.Provider = {
$$typeof: REACT_PROVIDER_TYPE,
_context: context
}
var Consumer = {
$$typeof: REACT_CONTEXT_TYPE,
_context: context
}
return context
}调用createContext方法后会创建一个context对象。 然后react处理Provider组件时,大致过程是jsx转成render function,执行render function生成vdom即ReactElement对象,通过reconcile转成fiber,之后commit更改页面dom来渲染。在reconcile转fiber过程中会进行处理,将传入的value赋值给_context._currentValue,这就完成了context的更新。 react调用useContext时,就是从传入的context对象引用中拿出_currentValue值来。
当然在react中context还需要考虑组件边界问题,即上下层的context不能相互影响**(同一个context 多个Provider时)**。 这是通过栈来处理的,Provider的reconcile过程中,beginWork时更新context之前有一个push操作。等到结束之后completeWork时,会有一个pop操作。 这样就很好理解了:子组件在取context时,从栈顶取值,保证了一定是离自己最新的context,然后provider的completeWork时会移除栈顶context,这样其他的子组件并不会被影响到。