共计 3454 个字符,预计需要花费 9 分钟才能阅读完成。
react hooks 的更新外围,其实是一个链表的钩子。
目前能够确定,useRef 和 useState 相似,每一个 useState/useRef 都能够了解为一个钩子,钩子(指针)存储在 workInProgressHook 中
能够回顾一下 useRef 的源码:react hooks 实质摸索 – useRef 源码详解
初始化 workInProgressHook 代码如下(中文正文为笔者增加的正文,英文正文为源代码里的正文)
function mountWorkInProgressHook() { | |
// 新建链表结点 | |
var hook = { | |
memoizedState: null, | |
baseState: null, | |
baseQueue: null, | |
queue: null, | |
next: null | |
}; | |
// workInProgressHook 能够了解为链表的指针 | |
// 个别状况:指针指的不是链表的结尾 | |
if (workInProgressHook !== null) { | |
// 把新的 hook 赋值给以后 workInProgressHook 的 next | |
workInProgressHook.next = hook; | |
// 让以后的指针指向下一个钩子 | |
workInProgressHook = workInProgressHook.next | |
} | |
// 非凡状况:指针指的是 null,阐明链表未建设。if (workInProgressHook === null) { | |
// 让指针指向 hook | |
workInProgressHook = hook; | |
// 这里先不去管他,currentlyRenderingFiber$1 应该是优化渲染局部的 | |
currentlyRenderingFiber$1.memoizedState = workInProgressHook; | |
} | |
// 返回指针 | |
return workInProgressHook; | |
} |
总结来说,等于是把链表的 next 指向一个新的 hook,同时返回了这个链表的表尾。
以上就是初始化 useRef/useState 干的事件。
接下来看更新时,useRef/useState 干了什么:
因为代码比拟长,能够先看一个步骤图理解一下步骤拆解
上面看源码(中文正文为笔者增加的正文,英文正文为源代码里的正文):
function updateWorkInProgressHook() { | |
// This function is used both for updates and for re-renders triggered by a | |
// render phase update. It assumes there is either a current hook we can | |
// clone, or a work-in-progress hook from a previous render pass that we can | |
// use as a base. When we reach the end of the base list, we must switch to | |
// the dispatcher used for mounts. | |
var nextCurrentHook; | |
// 这里在 workInProgressHook 之外,引入了一个新的概念:currentHook | |
// 然而这个概念能够不必管,因为这是 fiber 的概念。咱们本次不须要晓得 fiber 的概念 | |
if (currentHook === null) { | |
var current = currentlyRenderingFiber$1.alternate; | |
if (current !== null) {nextCurrentHook = current.memoizedState;} else {nextCurrentHook = null;} | |
} else {nextCurrentHook = currentHook.next;} | |
// 来到咱们相熟的 workInProgressHook | |
var nextWorkInProgressHook; | |
// 以下这块代码,是为了初始化 nextWorkInProgressHook | |
// 非凡状况:链表结尾。如果以后的指针指向为空,阐明为结尾。留神这里判断的是 workInProgressHook | |
if (workInProgressHook === null) { | |
// 为什么这么赋值,也跟 fiber 无关。能够先不论 | |
nextWorkInProgressHook = currentlyRenderingFiber$1.memoizedState; | |
} else { | |
// 如果不是链表结尾,那么会让 nextWorkInProgressHook 等于以后链表指针的 next,很好了解 | |
nextWorkInProgressHook = workInProgressHook.next; | |
} | |
// 这个模块是为了让 workInProgressHook 失常地指向下一个链表节点 | |
// 失常状况:初始化 nextWorkInProgressHook 后,nextWorkInProgressHook 不为空 | |
if (nextWorkInProgressHook !== null) { | |
// 这部分逻辑就是失常将 workInProgressHook 指针指向下一个元素 | |
// There's already a work-in-progress. Reuse it. | |
workInProgressHook = nextWorkInProgressHook; | |
// nextWorkInProgressHook 在这个办法里不再用到,然而一个全局变量,其余中央可能用到。nextWorkInProgressHook = workInProgressHook.next; | |
currentHook = nextCurrentHook; | |
} else { | |
// 非凡状况:初始化 nextWorkInProgressHook 后,nextWorkInProgressHook 依然为空 | |
// 可能有两种状况:// 1.workInProgressHook 为空(代表链表为空),currentlyRenderingFiber$1.memoizedState 为空 | |
// 2.workInProgressHook 不为空,以后指针指向了链表的尾部,所以 workInProgressHook.next 为空,导致 nextWorkInProgressHook 为空。// 不论链表为空,还是指向了结尾,形象意义上都是指向了链表结尾。// 这两种状况,最初都执行了 workInProgressHook = newHook; | |
// 这一块都是解决 fiberNode,能够不论 | |
// Clone from the current hook. | |
if (!(nextCurrentHook !== null)) { | |
{throw Error( "Rendered more hooks than during the previous render."); | |
} | |
} | |
currentHook = nextCurrentHook; | |
var newHook = { | |
memoizedState: currentHook.memoizedState, | |
baseState: currentHook.baseState, | |
baseQueue: currentHook.baseQueue, | |
queue: currentHook.queue, | |
next: null | |
}; | |
// 解决链表为空的状况 | |
// 这里要留神,如果 nextWorkInProgressHook 不为空,那么 workInProgressHook 也肯定不为空。所以这里隐含了一个条件:// workInProgressHook 和 nextWorkInProgressHook 都为空。if (workInProgressHook === null) { | |
// 这里稍稍改写下,把间断赋值分成了两局部 | |
// 链表为空,就须要把第一个元素赋值给指针,让链表指针失常 | |
// This is the first hook in the list. | |
workInProgressHook = newHook; | |
// fiber 相干 | |
currentlyRenderingFiber$1.memoizedState = workInProgressHook; | |
} else { | |
// 以后指针指向了链表的尾部的状况 | |
// 这里做了简略的改写 | |
// Append to the end of the list. | |
workInProgressHook.next = newHook; | |
// 能够看到,workInProgressHook = newHook 是必然执行的。也要留神,这里是在两个 else 里。workInProgressHook = newHook; | |
} | |
} | |
return workInProgressHook; | |
} |
正文完