Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React(16.8.6)源码之上下文传递(栈) #9

Open
mengxiong10 opened this issue May 16, 2019 · 0 comments
Open

React(16.8.6)源码之上下文传递(栈) #9

mengxiong10 opened this issue May 16, 2019 · 0 comments
Labels

Comments

@mengxiong10
Copy link
Owner

mengxiong10 commented May 16, 2019

上下文传递(栈)

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>;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant