在第一篇文章里我们了解了初次渲染过程react内部的处理流程和执行机制,接下里继续看看在状态更新阶段react是怎么处理的
现在触发demo中onclick事件,也就是执行setCount方法
同样从两个基础hook出发
- useState
- useEffect
更新阶段核心流程
useState
在开始之前我们带着两个问题:
- 执行setCount后,内部发生了什么?
- 如果多次执行setCount,它是怎么样取到最新的值的?
首先解答第一个问题
在第一篇文章说到了,在mountState阶段会绑定一个叫dispatchAction
的方法然后作为参数返回,这个方法在我们的demo中就是setCount方法,没有印象的看下下面的代码
function mountState(initialState) {
// 还记不记得这个熟悉的方法
var dispatch = queue.dispatch = dispatchAction.bind(null, currentlyRenderingFiber$1, queue);
return [hook.memoizedState, dispatch];
}
继续深入看下diapatchAction干了什么
function dispatchAction(fiber, queue, action) {
var update = {
expirationTime: expirationTime,
action: action,
next: null
};
// 处理当前hook的queue队列
var pending = queue.pending;
if (pending === null) {
update.next = update;
} else {
update.next = pending.next;
pending.next = update;
}
queue.pending = update;
// 进入调度环节
scheduleWork(fiber, expirationTime);
}
}
其实干了两件事
- 创建update节点,连接到当前hook(也就是useState)的queue后面(
这个queue忘记的伙伴可以翻回第一篇文章中看看
),这样每次调用dispatchAction都会在后面连接一个update节点,从而生成一个更新队列(这个更新队列后面会详细讲
) - 然后开始这一轮的scheduleWork调度(
关于调度做了什么详看这篇文章,因为内容非常多,这里不做过多说明:https://segmentfault.com/a/1190000020737020?utm_source=tag-newest
),大概流程就是将所有更新任务按照优先级排列,最后遍历整个fiberTree执行更新操作,更新阶会调用beginWork
方法,这就又回到了我们初次渲染的流程,因为初次渲染时也会调用这个方法,就对应起来我们第一篇文章的初次渲染流程图
我们继续走
按照上面的流程会走到这一步,又是熟悉的代码,此时我们会把HooksDispatcherOnUpdateInDEV
赋值到dispatcher
上
{
// 首次执行currentDispatcher = null,所以进入else分支;在更新阶段会进入if分支
if (currentDispatcher !== null) {
currentDispatcher = HooksDispatcherOnUpdateInDEV;
} else {
currentDispatcher = HooksDispatcherOnMountInDEV;
}
}
继续看看HooksDispatcherOnUpdateInDEV
是什么
HooksDispatcherOnUpdateInDEV = {
useCallback: function (callback, deps) {
return updateCallback(callback, deps);
},
useEffect: