React 的更新流程分为 Render 阶段(协调阶段)和 Commit 阶段(提交阶段),两者共同完成组件更新。以下是每个阶段的核心职责和实现细节:
一、Render 阶段(协调阶段)
目标:生成更新计划(副作用链表),不直接操作 DOM
特性:可中断、异步执行(并发模式核心)
核心流程:
-
触发更新:
setState
、useState
、父组件渲染等触发更新- 创建
Update
对象,加入Fiber
的更新队列
-
调度优先级:
- 根据更新来源(用户交互、网络响应等)分配优先级(如
Immediate
、UserBlocking
) - 通过
scheduler
调度任务
- 根据更新来源(用户交互、网络响应等)分配优先级(如
-
协调算法(Reconciliation):
graph TD A[根节点开始] --> B{是否还有子节点?} B -->|是| C[处理当前Fiber节点] C --> D[比较新旧props/state] D --> E[标记副作用Tag] E --> B B -->|否| F[完成协调]
- 深度优先遍历:从根节点开始遍历 Fiber 树
- Diff 算法:对比新旧
ReactElement
,生成子 Fiber 树 - 副作用标记:对需要 DOM 操作的节点打标记(如
Placement
、Update
、Deletion
)
-
收集副作用:
- 构建副作用链表(
effectList
),链表节点包含所有需要 DOM 操作的 Fiber
- 构建副作用链表(
关键代码:
function performUnitOfWork(fiber) {
// 1. 执行组件渲染(生成子Fiber)
const children = reconcileChildren(fiber, fiber.props.children);
// 2. Diff算法比较新旧子节点
reconcileChildFibers(fiber, children);
// 3. 返回下一个工作单元(深度优先)
if (fiber.child) return fiber.child;
let nextFiber = fiber;
while (nextFiber) {
if (nextFiber.sibling) return nextFiber.sibling;
nextFiber = nextFiber.return;
}
}
二、Commit 阶段(提交阶段)
目标:将 Render 阶段的更新计划同步应用到 DOM
特性:同步执行、不可中断(防止页面状态不一致)
核心流程:
-
预处理:
- 调用
getSnapshotBeforeUpdate
生命周期(获取 DOM 更新前的状态)
- 调用
-
DOM 操作:
graph TD A[遍历effectList] --> B{操作类型} B -->|Placement| C[插入DOM] B -->|Update| D[更新DOM属性] B -->|Deletion| E[删除DOM] C --> F D --> F E --> F[完成所有DOM操作]
- 实际执行 DOM 增删改操作
- 处理
ref
的绑定/解绑
-
生命周期与副作用:
- 同步执行:
componentDidMount
、componentDidUpdate
- 异步调度:
useEffect
副作用(通过scheduleCallback
调度)
- 同步执行:
-
状态清理:
- 重置 Fiber 树的副作用标记
- 准备下一次更新的
current
树
关键代码:
function commitRoot(root) {
// 1. 处理DOM插入/更新/删除
commitMutationEffects(root.effectList);
// 2. 执行生命周期
commitLayoutEffects(root.effectList);
// 3. 调度useEffect
schedulePendingEffects();
}
三、阶段对比
特性 | Render 阶段 | Commit 阶段 |
---|---|---|
操作对象 | Fiber 树(虚拟节点) | 真实 DOM |
可中断性 | 是(并发模式) | 否 |
副作用 | 收集副作用(effectList) | 执行副作用(DOM操作/生命周期) |
优先级 | 支持优先级插队 | 无优先级,必须同步完成 |
生命周期 | 无 | componentDidMount/Update |
主要耗时 | 计算 Diff | DOM 操作 |
四、示例流程
假设组件树更新:
// 更新前
<div>
<span key="1">Old</span>
</div>
// 更新后
<div>
<span key="1">New</span>
<p key="2">New</p>
</div>
-
Render 阶段:
- 比较新旧节点,标记
<span>
为Update
,<p>
为Placement
- 生成
effectList
:[spanFiber, pFiber]
- 比较新旧节点,标记
-
Commit 阶段:
- 更新
<span>
的文本内容 - 插入新
<p>
节点到<div>
- 更新
五、设计意义
- 并发模式基础:Render 阶段可中断,确保高优先级任务(如用户输入)及时响应
- 性能优化:分离计算和 DOM 操作,避免计算阻塞渲染
- 一致性保证:Commit 阶段一次性提交,防止中间状态暴露
通过这种两阶段设计,React 平衡了性能与一致性,为复杂应用的流畅体验提供底层保障。