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.Provider 和 useContext。通过分析代码,可以看到这三部分之间的关系如下:
React Context 结构
Context
即通过 React.CreateContext 创建的对象,主要包括以下属性:
-
$$typeof:Symbol(react.context),标注此对象是一个Context。 -
Consumer: 使用 Context.Consumer 时访问的对象。 -
Provider: 使用Context.Provider时访问的对象。 -
_currentValue:context当前的值,受Context.Provider的影响。
Context.Provider
主要有以下的属性:
-
$$typeof:Symbol(react.provider),标记此对象是一个Context.Provider。 -
_context: 指向当前Provider的Context
useContext
useContext 返回 _currentValue 提供给使用的组件。通过源码解析发现,每次读取 context 都会向 lastContextDependency 推送数据。笔者未发现 React 从里面读取数据。这个数据结构的作用有待探查。
基本流程
每次 Context.Provider 的 beginWork 会向 valueStack 的栈里推送数据。在 Context.Provider 的 completeUnitOfWork 的时候,会从 valueStack 的栈里抛出数据。需要注意的是,
- 最新的
context值在这个数据结构中没有存储。 - 最新的
context值之前的值存储在valueCursor.current中。 - 除此之外的值才存储在
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 中其它的值的作用。笔者准备在后续的文章中继续做探索。