Appearance
第 3.1 节:从 setState 到渲染:概览
在 React 的世界里,UI 是状态的映射。当我们通过 setState 或 dispatch 改变组件的状态时,React 会启动一个复杂的、精心设计的流程,以确保 UI 高效、一致地更新。这个从状态变更到屏幕像素变化的过程,我们称之为“一次更新的黄金路径”(The Golden Path of an Update)。
理解这条路径对于深入 React 内部机制至关重要。它将我们之前学到的所有概念——Fiber、Lanes、Scheduler、Reconciler——串联成一个完整的故事。
黄金路径的四个核心阶段
一次典型的 React 更新可以被划分为四个主要的、连续的阶段。让我们以一个简单的点击事件触发 useState 的 setCount 为例,来概览这条路径。
jsx
function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}当用户点击按钮时,setCount(1) 被调用,黄金路径就此开启。
阶段一:创建与调度(Creation & Scheduling)
创建 Update 对象:首先,
setCount(1)这个调用不会立即改变count的值。React 会将这次更新封装成一个Update对象。这个对象包含了更新的载荷(payload,即1)、优先级(Lane)等信息。入队(Enqueue):这个
Update对象会被添加(enqueue)到触发更新的组件所对应的 Fiber 节点的updateQueue中。调度任务(Schedule Task):React 会请求调度器(Scheduler)来安排一个新的渲染任务。它不会立即开始工作,而是根据更新的优先级(例如,用户交互触发的更新是高优先级的
SyncLane)来决定何时执行。
核心职责:将用户的更新意图转化为一个可被 React 理解和调度的内部任务。
涉及模块:ReactFiberHooks.js, ReactFiberClassUpdateQueue.js, ReactFiberWorkLoop.js
阶段二:渲染(Render Phase)
当调度器决定执行这个任务时,React 就进入了渲染阶段(Render Phase)。这个阶段是异步、可中断的,其核心目标是构建一棵新的“WIP(work-in-progress)”Fiber 树。
开始工作循环(Begin Work Loop):从应用的根节点(Root Fiber)开始,React 启动一个深度优先的遍历。
构建 WIP 树:对于每个 Fiber 节点,React 会:
- 调用
createWorkInProgress创建或复用其alternate节点。 - 处理
updateQueue中的Update对象,计算出新的 state。 - 调用组件的
render方法(对于类组件)或直接执行函数组件,获取新的ReactElement。 - Diffing:将新的
ReactElement与旧的子 Fiber 节点进行比较(Diffing),并为新的子节点创建或更新对应的 Fiber 节点。
- 调用
标记副作用(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 操作的原子性和一致性。
切换 Fiber 树:React 将根节点的
current指针指向刚刚构建完成的 WIP 树,使其成为新的current树。执行副作用:React 会遍历新的
current树(也就是刚刚的 WIP 树),并根据之前标记的flags,一次性地执行所有 DOM 操作:Placement:插入新的 DOM 节点。Update:更新 DOM 节点的属性。Deletion:删除不再需要的 DOM 节点。
调用生命周期/Hooks:在这个阶段,
useLayoutEffect的回调会同步执行。而useEffect的回调则会被推入一个队列,在稍后的浏览器空闲时间异步执行。
核心职责:将 Render 阶段计算出的变更,真实地、同步地应用到 DOM 上,并触发生命周期方法和 effect。
涉及模块:ReactFiberCommitWork.js
阶段四:空闲(Idle)
提交阶段完成后,本次更新的黄金路径就走完了。React 将控制权交还给浏览器,等待下一次更新的到来。
流程图概览
接下来的章节,我们将深入到每个阶段的源码细节中,探索 React 是如何以如此高效和优雅的方式完成这一切的。