综述
书接上一章节: React 源码探源 3 Update 的整体流程. 原有的代码和相关的流程图不在赘述。本节来细究一下 useState 相关的流程。
fiber 与 useState hook 结构
fiber 与 useState hook 结构
有图中可以看到,一个组件的所有 hook 都存储在 fiber 的 memorizedState 下面的队列中,hook 按照出现的顺序通过 next 存储成单向链表。每个 hook 中会存储当前需要执行的 update 所形成的单向循环链表。
update 的结构如下:
-
pending: 指向下一个更新,因为是循环链表,链表尾会指向链表头。 -
action: 需要执行的更新, 即setState传递的响应函数。 -
eagerState: 如果组件没有更新过,会在执行setState时计算下一个state的值,否则会在执行下一次
的render组件时的useState时才会计算。
初始化过程
render 和更新流程
初次渲染,当调用
useState 时,会调用 HooksDispatcherOnMountInDEV 的 mountState,返回两个值,第一个是 hook.memorizedState,即当前 hook 的值。第二个是 dispatchAction,绑定三个参数
-
action,setState的回调函数,初始化时为 null. -
queue, 当前hooks挂载的更新队列. -
fiber, 当前的 fiber.
更新过程
当事件触发后,会调用事件响应中的 setState 函数,实际上是初始化时生成的第二个返回值 dispatchAction,执行后标记改组件有所更新,详情请参考上一节。当再次执行到 fiber(Dev) 时,会调用 HooksDispatcherOnUpdateInDEV 的 updateState 函数,会执行更新队列中剩余的更新。
state 更新后,其自组件再根据传递的 props 不同重新渲染。
scheduleMicrotask
通过通读代码发现, flushSyncCallbacks 可能会通过 scheduleMicrotask 执行。即在本次调用栈清空以后,下一次浏览器渲染之前执行。观察源码可以发现会按照以下三种方式进行尝试
-
queueMicrotask,可以看到在浏览器兼容的情况下, 此 API 对
microtask支持的最好 -
Promise.resolve(null).then(callback),容易得知,Promise.then的回调会向micotask队列推送任务。 -
setTimeout(callback, 0),浏览器会选中增加setTimeout回调的事件,造成不必要的延迟。











网友评论