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
。通过分析代码,可以看到这三部分之间的关系如下:
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
:
如果有三层嵌套:
三层嵌套
作为参考,最后的 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
中其它的值的作用。笔者准备在后续的文章中继续做探索。