协调与渲染流程
约 1233 字大约 4 分钟
布欧-Lewyon
2026-05-15
协调(Reconciliation)是 React 将虚拟 DOM 变化同步到真实 DOM 的全过程。本文以 setState 为起点,完整追踪一次"更新"的全流程。
一次更新的完整路径
第一步:创建 Update 对象
Class 组件中的 setState
// Component.prototype.setState
Component.prototype.setState = function (partialState, callback) {
this.updater.enqueueSetState(this, partialState, callback, 'setState');
};
// 内部 enqueueSetState
function enqueueSetState(inst, payload, callback) {
const fiber = getInstance(inst);
const update = createUpdate(eventTime, lane);
update.payload = payload; // { count: 1 } 或函数 (prev) => newState
update.callback = callback;
// 插入 fiber 的 updateQueue
enqueueUpdate(fiber, update);
// 触发调度
scheduleUpdateOnFiber(fiber, lane, eventTime);
}Function 组件中的 useState dispatch
function dispatchSetState(fiber, queue, action) {
const update = {
lane,
action, // 新的值 或 (prev) => newValue
next: null,
};
// 插入环形链表
const pending = queue.pending;
if (pending === null) {
update.next = update; // 自环
} else {
update.next = pending.next;
pending.next = update;
}
queue.pending = update;
// 触发调度
const root = scheduleUpdateOnFiber(fiber, lane, eventTime);
}Update 链表
Update 以环形链表存储,queue.pending 指向最后一个 Update。
计算出最终的 state 状态:
baseState = 0
Update1: { count: 1 } → memoizedState = 1
Update2: { count: 2 } → memoizedState = 3
Update3: { count: 3 } → memoizedState = 6第二步:调度到 Render 阶段
function scheduleUpdateOnFiber(fiber, lane) {
const root = markUpdateLaneFromFiberToRoot(fiber); // 向上找到 rootFiber
markRootUpdated(root, lane); // root 上标记 Lane
if (lane === SyncLane) {
// 同步模式:flushSync 或在 Legacy 模式下走这里
performSyncWorkOnRoot(root);
} else {
// 并发模式:交给 Scheduler
ensureRootIsScheduled(root);
}
}时间切片
// Scheduler 内部
function workLoopConcurrent() {
while (workInProgress !== null && !shouldYield()) {
performUnitOfWork(workInProgress);
}
}
function shouldYield(): boolean {
// 当前帧的剩余时间 < 5ms
return getCurrentTime() >= deadline;
}第三步:Render —— beginWork
beginWork 是每个 Fiber 节点的处理入口:
function beginWork(current: Fiber | null, workInProgress: Fiber): Fiber | null {
// 1. 检查是否需要更新
if (current !== null) {
const oldProps = current.memoizedProps;
const newProps = workInProgress.pendingProps;
// 如果 props 和 context 都没变 → 跳过(性能优化)
if (oldProps === newProps && !hasContextChanged()) {
return bailoutOnAlreadyFinishedWork(current, workInProgress);
}
}
// 2. 根据 tag 分发到不同处理函数
switch (workInProgress.tag) {
case FunctionComponent: {
return updateFunctionComponent(current, workInProgress);
}
case ClassComponent: {
return updateClassComponent(current, workInProgress);
}
case HostComponent: { // 原生标签 <div> <span>
return updateHostComponent(current, workInProgress);
}
// ...
}
return null;
}updateFunctionComponent —— 函数组件的执行
function updateFunctionComponent(current, workInProgress, Component, nextProps) {
// 1. 执行函数组件本身(运行 Hooks)
const nextChildren = renderWithHooks(
current,
workInProgress,
Component, // 例如 function MyComp() { ... }
nextProps,
// 第二个参数
);
// 2. 校验 Hooks 执行顺序(开发环境)
if (current !== null && !didReceiveUpdate) {
// bailout
}
// 3. reconcile 子节点
reconcileChildren(current, workInProgress, nextChildren);
return workInProgress.child;
}renderWithHooks —— Hooks 链
function renderWithHooks(current, workInProgress, Component, props) {
// 将全局变量指向当前 Fiber
currentlyRenderingFiber = workInProgress;
workInProgress.memoizedState = null; // 重置 Hooks 链表
// React 内部 Hooks dispatcher
ReactCurrentDispatcher.current =
current === null
? HooksDispatcherOnMount
: HooksDispatcherOnUpdate;
// 执行组件函数 → 触发 useState/useEffect 等
const children = Component(props);
// 检查 Hooks 数量是否匹配(校验 Rules of Hooks)
// ...
return children;
}第四步:Render —— completeWork
子节点处理完成后,回到自身做收尾工作:
function completeWork(current, workInProgress) {
switch (workInProgress.tag) {
case HostComponent: {
const instance = createInstance(type, newProps);
// 将子 DOM 添加到当前节点
appendAllChildren(instance, workInProgress);
workInProgress.stateNode = instance;
// 处理事件监听
if (finalizeInitialChildren(instance, type, newProps)) {
// 需要 focus / autoFocus
}
return null;
}
}
}第五步:Commit —— mutation 阶段
before mutation
function commitBeforeMutationEffects(firstChild: Fiber) {
let fiber = firstChild;
while (fiber) {
if (fiber.flags & Snapshot) {
// 调用 getSnapshotBeforeUpdate(类组件)
const instance = fiber.stateNode;
const snapshot = instance.getSnapshotBeforeUpdate(
fiber.alternate.memoizedProps,
fiber.alternate.memoizedState,
);
instance.__reactInternalSnapshotBeforeUpdate = snapshot;
}
// 递归处理子节点
commitBeforeMutationEffects(fiber.child);
fiber = fiber.sibling;
}
}mutation —— 真正操作 DOM
function commitMutationEffects(root, renderPriorityLevel) {
while (nextEffect !== null) {
const flags = nextEffect.flags;
// 1. 增
if (flags & Placement) {
// insertOrAppendPlacementNode(nextEffect)
}
// 2. 更新
if (flags & Update) {
// commitWork(nextEffect) — 更新 DOM 属性
}
// 3. 删
if (flags & Deletion) {
// commitDeletion(nextEffect)
// 调用 useEffect cleanup
}
nextEffect = nextEffect.sibling;
}
}layout —— useLayoutEffect & ref
function commitLayoutEffects(root, renderPriorityLevel) {
while (nextEffect !== null) {
const flags = nextEffect.flags;
if (flags & Update) {
const current = nextEffect.alternate;
// 1. 执行 useLayoutEffect
commitHookLayoutEffects(nextEffect, HookLayout);
// 2. 设置 ref
if (nextEffect.ref !== null) {
safelyDetachRef(current);
safelyAttachRef(nextEffect);
}
// 3. 执行 setState 回调
commitUpdateQueue(nextEffect, ...);
}
nextEffect = nextEffect.sibling;
}
}数据流总结
关键模块代码入口
| 模块 | 文件路径 (React 源码 packages) | 关键函数 |
|---|---|---|
| Fiber 创建 | react-reconciler/src/ReactFiber.js | createFiberFromElement |
| 调度 | react-reconciler/src/ReactFiberWorkLoop.js | scheduleUpdateOnFiber |
| beginWork | react-reconciler/src/ReactFiberBeginWork.js | beginWork, updateFunctionComponent |
| completeWork | react-reconciler/src/ReactFiberCompleteWork.js | completeWork |
| Diff | react-reconciler/src/ReactChildFiber.js | reconcileChildFibers |
| Commit | react-reconciler/src/ReactFiberCommitWork.js | commitRootImpl |
| Hooks | react-reconciler/src/ReactFiberHooks.js | renderWithHooks, updateState |
| Lane 优先级 | react-reconciler/src/ReactFiberLane.js | requestUpdateLane |
小结
一次 setState → 用户看到新 UI 的完整链路:
setState → enqueueUpdate → scheduleUpdateOnFiber → Scheduler →
performUnitOfWork(可中断) → beginWork → reconcileChildren → completeWork →
commitRoot → beforeMutation → mutation(操作DOM) → layout(useLayoutEffect) →
浏览器绘制 → useEffect 异步执行下一节:Diff 算法详解
