前端技术

React 源码探源 6 useContext

2021-07-11  本文已影响0人  吴摩西

背景

上回,本章开始研究 useContext 相关的内容。useContext 使得隔多层的父节点传递给子节点属性成为可能。

基本使用

使用 useContext 的基本模式如下

// define context
const UserNameContext = React.createContext();
// use the Dev
function Dev() {
    const userName = React.useContext(UserNameContext);
    return userName.name; // return Joe
}
// provide a context
function App() {
    return (<UserNameContext.Provider value={{name: 'Joe'}}>
        <Dev />
    </ThemeContext>);
}

基本结构

通过上面的代码可以看到useContext 总共分为三部分 Context, Context.ProvideruseContext。通过分析代码,可以看到这三部分之间的关系如下:

React Context 结构

Context

即通过 React.CreateContext 创建的对象,主要包括以下属性:

Context.Provider

主要有以下的属性:

useContext

useContext 返回 _currentValue 提供给使用的组件。通过源码解析发现,每次读取 context 都会向 lastContextDependency 推送数据。笔者未发现 React 从里面读取数据。这个数据结构的作用有待探查。

基本流程

每次 Context.ProviderbeginWork 会向 valueStack 的栈里推送数据。在 Context.ProvidercompleteUnitOfWork 的时候,会从 valueStack 的栈里抛出数据。需要注意的是,

  1. 最新的 context 值在这个数据结构中没有存储。
  2. 最新的 context 值之前的值存储在 valueCursor.current 中。
  3. 除此之外的值才存储在 valueStack 中。
    举例来讲,第一次使用 Context.Provider时:
    Screen Shot 2021-07-11 at 10.17.40 AM.png

在其中嵌套使用 Context.Provider

嵌套 Context.Provider

如果有三层嵌套:


三层嵌套

作为参考,最后的 valueStack 使用的代码如下:

const UserNameContext = React.createContext();
const Provider = UserNameContext.Provider;
function Deep2() {
  const userName = React.useContext(UserNameContext);
  return userName.name;
}
function Deep() {
  const userName = React.useContext(UserNameContext);
  return (<Provider value={userName}>
    <Deep2 />
  </Provider>);
}
function Dev() {
  const userName = React.useContext(UserNameContext);
  return (<div id="div">
    <div>{userName.name}</div>
      <Provider value={userName}>
        <Deep />
      </Provider>
   </div>);
}
function App() {
  const [name, setName] = React.useState('Joe');
  return (
    <Provider value={{ name: name }}>
      <Dev />
    </Provider>
  );
}

后续

本文较为浅显的探讨了 useContext 的相关数据结构与流程。不过也留下了一些没有探讨的结构,其中比较重要的是 valueStack 中其它的值的作用。笔者准备在后续的文章中继续做探索。

上一篇下一篇

猜你喜欢

热点阅读