Skip to content

第 3.1 节:从 setState 到渲染:概览

在 React 的世界里,UI 是状态的映射。当我们通过 setStatedispatch 改变组件的状态时,React 会启动一个复杂的、精心设计的流程,以确保 UI 高效、一致地更新。这个从状态变更到屏幕像素变化的过程,我们称之为“一次更新的黄金路径”(The Golden Path of an Update)。

理解这条路径对于深入 React 内部机制至关重要。它将我们之前学到的所有概念——Fiber、Lanes、Scheduler、Reconciler——串联成一个完整的故事。

黄金路径的四个核心阶段

一次典型的 React 更新可以被划分为四个主要的、连续的阶段。让我们以一个简单的点击事件触发 useStatesetCount 为例,来概览这条路径。

jsx
function Counter() {
  const [count, setCount] = useState(0);

  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

当用户点击按钮时,setCount(1) 被调用,黄金路径就此开启。

阶段一:创建与调度(Creation & Scheduling)

  1. 创建 Update 对象:首先,setCount(1) 这个调用不会立即改变 count 的值。React 会将这次更新封装成一个 Update 对象。这个对象包含了更新的载荷(payload,即 1)、优先级(Lane)等信息。

  2. 入队(Enqueue):这个 Update 对象会被添加(enqueue)到触发更新的组件所对应的 Fiber 节点的 updateQueue 中。

  3. 调度任务(Schedule Task):React 会请求调度器(Scheduler)来安排一个新的渲染任务。它不会立即开始工作,而是根据更新的优先级(例如,用户交互触发的更新是高优先级的 SyncLane)来决定何时执行。

核心职责:将用户的更新意图转化为一个可被 React 理解和调度的内部任务。

涉及模块ReactFiberHooks.js, ReactFiberClassUpdateQueue.js, ReactFiberWorkLoop.js

阶段二:渲染(Render Phase)

当调度器决定执行这个任务时,React 就进入了渲染阶段(Render Phase)。这个阶段是异步、可中断的,其核心目标是构建一棵新的“WIP(work-in-progress)”Fiber 树。

  1. 开始工作循环(Begin Work Loop):从应用的根节点(Root Fiber)开始,React 启动一个深度优先的遍历。

  2. 构建 WIP 树:对于每个 Fiber 节点,React 会:

    • 调用 createWorkInProgress 创建或复用其 alternate 节点。
    • 处理 updateQueue 中的 Update 对象,计算出新的 state。
    • 调用组件的 render 方法(对于类组件)或直接执行函数组件,获取新的 ReactElement
    • Diffing:将新的 ReactElement 与旧的子 Fiber 节点进行比较(Diffing),并为新的子节点创建或更新对应的 Fiber 节点。
  3. 标记副作用(Mark Effects):在 Diffing 过程中,如果发现需要对 DOM 进行变更(如插入、更新、删除),React 不会立即执行它。相反,它会在对应的 WIP Fiber 节点上添加一个 flag(副作用标记)。

核心职责:找出 UI 的哪些部分需要改变,并在内存中构建出“未来”的 UI 结构(WIP 树),同时标记出所有需要执行的 DOM 操作。

涉及模块ReactFiberWorkLoop.js, ReactFiberBeginWork.js, ReactFiberCompleteWork.js

阶段三:提交(Commit Phase)

当整棵 WIP 树都构建完成后,React 就进入了提交阶段(Commit Phase)。这个阶段是同步、不可中断的,以保证 DOM 操作的原子性和一致性。

  1. 切换 Fiber 树:React 将根节点的 current 指针指向刚刚构建完成的 WIP 树,使其成为新的 current 树。

  2. 执行副作用:React 会遍历新的 current 树(也就是刚刚的 WIP 树),并根据之前标记的 flags,一次性地执行所有 DOM 操作:

    • Placement:插入新的 DOM 节点。
    • Update:更新 DOM 节点的属性。
    • Deletion:删除不再需要的 DOM 节点。
  3. 调用生命周期/Hooks:在这个阶段,useLayoutEffect 的回调会同步执行。而 useEffect 的回调则会被推入一个队列,在稍后的浏览器空闲时间异步执行。

核心职责:将 Render 阶段计算出的变更,真实地、同步地应用到 DOM 上,并触发生命周期方法和 effect。

涉及模块ReactFiberCommitWork.js

阶段四:空闲(Idle)

提交阶段完成后,本次更新的黄金路径就走完了。React 将控制权交还给浏览器,等待下一次更新的到来。

流程图概览

接下来的章节,我们将深入到每个阶段的源码细节中,探索 React 是如何以如此高效和优雅的方式完成这一切的。

Last updated: