xdm,又要到饭了,又更新代码了!
总结一下上一篇完成的内容,
- 完成了useSyncExternalStore的实现, 从底层理解运行机制。
有兴趣的可以点这里查看useSyncExternalStore的实现, 从底层理解运行机制
这一篇,我们从0-1 实现 useContext,先来一波代码演示一下平日如何使用的,
const MyContext = createContext('default value')
function A() {
return (
<MyContext.Provider value="A value">
<B />
</MyContext.Provider>
)
}
function B() {
return (
<MyContext.Provider value="B value">
<C />
</MyContext.Provier>
)
}
function C() {
const value = useContext(MyContext)
return <div>{value}</div> // B 的值
}
function E() {
const value = useContext(MyContext)
return <div>{value}</div> // default value
}
根据上面的代码可以知道,
- createContext 返回一个组件 context, context 有一个属性即Provider 函数,所以可以使用 <MyContext.Provider> 进行渲染,即函数组件
- 每次使用<MyContext.Provider value="any value">, 包裹里面的组件可以使用提供的value值。
- 但是每次用了之后,需要回退原始值,上面的代码里面的E组件就是一个独立组件,如果不这样做,E组件获取的就是B value, 而不是default value
实现 createContext
fucntion createContext(defaultValue) {
const context = {
defaultValue,
Provider: function({value, children}) {
const fiber = workInProgress // 当前渲染的 fiber node
const previousValue = fiber.contexts ? fiber.contexts[context] : undefined
if (!fiber.contexts) {
fiber.contexts = {}
}
fiber.contexts[context] = value
// renderComponent已经之前的文章里实现过了,有兴趣的可以查看
const renderChildren = renderComponent(children)
// 恢复之前的value
if (previousValue === undefined)
delete fiber.contexts[context]
else
fiber.contexts[context] = previousValue
}
return renderChildren
}
return context
}
实现 useContext
function useContext(context) {
const fiber = workInProgress
let currentContext = context.defaultValue;
let currentFiber = fiber
while(currentFiber) {
if (currentFiber.contexts && currentFiber.contexts[context]!==undefined) {
currentContext = currentFiber.contexts[context]
break
}
currentFiber = currentFiber.parent // 回溯父fiber进行查找
}
return currentContext
}
createContext / useContext 即从fiber进行遍历获取最近的context, 如果没有则使用默认值。从代码层面你可以了解,总是从子->父顺序层层进行查看,直至第一个context匹配。
如果这样的长度/强度你觉得可以接受,觉得有帮助,可以继续阅读下一篇,实现一个 Mini React:核心功能详解 - useContext的实现 。
建议
我们的源码层面没有使用堆栈结构解决内嵌等情况,如果有兴趣的小伙伴可以考虑实现一下。官方使用的就是堆栈结构。
那么下一篇将从0-1实现开发 useDeferredValue 。
如果文章对你有帮助,请点个赞支持一下!
啥也不是,散会。