blog
blog copied to clipboard
React(16.8.6)源码之上下文传递(栈)
上下文传递(栈)
React 的上下文传递都通过 valueStack 这个数组保存. 但是需要存储多种类型的数据(NewContext, HostContainer 等),配合游标(cursor)实现.
接口
- createCursor(defaultValue)
- isEmpty()
- pop(cursor, fiber)
- push(cursor, value, fiber)
// 游标的current保存当前的值;
// push的时候传入游标的值,索引+1, 游标的current再保存为最新传入的值;
// pop的时候取出valueStack当前位置的值交给游标, valueStack赋值null,索引-1;
// 这样相当于游标的值就是传统栈顶的值, 这样就不需要多个栈, 每次直接取游标的值就行了, 不用操作栈.
function createCursor(defaultValue) {
return {
current: defaultValue
};
}
function pop(cursor, fiber) {
cursor.current = valueStack[index];
valueStack[index] = null;
{
fiberStack[index] = null;
}
index--;
}
function push(cursor, value, fiber) {
index++;
valueStack[index] = cursor.current;
{
fiberStack[index] = fiber;
}
cursor.current = value;
}
NewContext (新的context Api)
function pushProvider<T>(providerFiber: Fiber, nextValue: T): void {
const context: ReactContext<T> = providerFiber.type._context
push(valueCursor, context._currentValue, providerFiber)
context._currentValue = nextValue
}
function popProvider(providerFiber: Fiber): void {
const currentValue = valueCursor.current
pop(valueCursor, providerFiber)
const context: ReactContext<any> = providerFiber.type._context
context._currentValue = currentValue
}
beginWork中遇到tag是ContextProvider时 pushProvider, 将value的值存在context._currentValue, 之后要 取context的值比如 useContext, 就是context._currentValue这个值.
为什么要将context入栈保存, 访问的不是context._currentValue吗?
如下考虑多个同样的context嵌套的情况. TestContext的value被改变2次, useContext(TestContext) 是取树中最近的 <TestContext.Provider>的值, 为了保证context._currentValue的值是正确的, 所以fiber的遍历顺序是深度优先, 在beginWork的时候入栈, 在completeWork的时出栈还原上一次的值. 保证每个组件会访问两次.
const TestContext = React.createContext<string>('');
function Test() {
return (
<TestContext.Provider value="before">
<TestContext.Provider value="after">
<Child />
</TestContext.Provider>
<Child />
</TestContext.Provider>
);
}
function Child() {
const value = useContext(TestContext);
return <span>{value}</span>;
}