React 源码探源 4 useState

综述

书接上一章节: React 源码探源 3 Update 的整体流程. 原有的代码和相关的流程图不在赘述。本节来细究一下 useState 相关的流程。

fiber 与 useState hook 结构

fiber 与 useState hook 结构

有图中可以看到,一个组件的所有 hook 都存储在 fibermemorizedState 下面的队列中,hook 按照出现的顺序通过 next 存储成单向链表。每个 hook 中会存储当前需要执行的 update 所形成的单向循环链表。
update 的结构如下:

  • pending: 指向下一个更新,因为是循环链表,链表尾会指向链表头。
  • action : 需要执行的更新, 即setState 传递的响应函数。
  • eagerState: 如果组件没有更新过,会在执行 setState 时计算下一个 state 的值,否则会在执行下一次
    render 组件时的 useState 时才会计算。

初始化过程

render 和更新流程

初次渲染,当调用 useState 时,会调用 HooksDispatcherOnMountInDEVmountState,返回两个值,第一个是 hook.memorizedState,即当前 hook 的值。第二个是 dispatchAction,绑定三个参数

  1. action, setState 的回调函数,初始化时为 null.
  2. queue, 当前 hooks 挂载的更新队列.
  3. fiber, 当前的 fiber.

更新过程

当事件触发后,会调用事件响应中的 setState 函数,实际上是初始化时生成的第二个返回值 dispatchAction,执行后标记改组件有所更新,详情请参考上一节。当再次执行到 fiber(Dev) 时,会调用 HooksDispatcherOnUpdateInDEVupdateState 函数,会执行更新队列中剩余的更新。

state 更新后,其自组件再根据传递的 props 不同重新渲染。

scheduleMicrotask

通过通读代码发现, flushSyncCallbacks 可能会通过 scheduleMicrotask 执行。即在本次调用栈清空以后,下一次浏览器渲染之前执行。观察源码可以发现会按照以下三种方式进行尝试

  1. queueMicrotask,可以看到在浏览器兼容的情况下, 此 API 对 microtask 支持的最好
  2. Promise.resolve(null).then(callback),容易得知, Promise.then 的回调会向 micotask 队列推送任务。
  3. setTimeout(callback, 0),浏览器会选中增加 setTimeout 回调的事件,造成不必要的延迟。

你可能感兴趣的:(React 源码探源 4 useState)