第一阶段已经完成了首轮 render + commit + passive effect 的闭环。接下来进入第二阶段:状态更新驱动的 Fiber 更新流程,也就是我们日常开发中调用 setStateuseStateuseReducer 后 React 如何处理状态更新的完整链路。本文严格基于 React 19 源码,解析更新是如何被调度、Fiber 如何复用、updateQueue 和 lanes 如何协作,以及最终如何触发 render 阶段。


一、dispatchAction:状态更新的入口

在函数组件中,当我们调用:

const [count, setCount] = useState(0)
setCount(prev => prev + 1)
  • setCount 实际上是通过 dispatchAction 创建的函数。
  • 它保存了对当前 Fiber 的引用以及对应的 updateQueue:
dispatchSetState(fiber, queue, action)

关键操作:

  1. 创建一个 update 对象:
const update = {
  action,      // setState 或 useReducer 的更新函数 / 值
  lane,        // 本次更新的优先级 lane
  next: null
}
  1. 将 update 加入 Fiber 的 updateQueue
  • 如果队列为空,直接挂上
  • 如果队列已存在,追加到循环链表中
  1. 调用调度函数:
scheduleUpdateOnFiber(fiber, lane, eventTime)

二、updateQueue:Fiber 上的状态队列

每个 Hook 对应一个 updateQueue(在 Fiber.memoizedState 中链表存储)。结构简化如下:

{
  baseState,      // 用于计算下一个状态的基础 state
  firstUpdate,    // 待处理更新链表头
  lastUpdate,     // 待处理更新链表尾
  dispatch        // setState 函数
}
  • 当我们调用 setState 时,更新会被加入 firstUpdate / lastUpdate
  • Fiber 的 memoizedState 链表对应 Hook 的状态
  • 更新会在下一次 render 阶段计算新的状态

三、scheduleUpdateOnFiber:Fiber 调度入口

scheduleUpdateOnFiber(fiber, lane, eventTime) 是 React 19 更新调度的核心入口。

核心职责:

  1. 标记 Fiber 的 lane,表示这个 Fiber 有 pending 更新:
fiber.lanes |= lane
  1. 确保 FiberRoot 在 rootSchedule 中
  • React 会把 FiberRoot 加入链表 firstScheduledRoot / lastScheduledRoot
  • 用微任务保证根调度任务被执行
  1. 调用调度器
  • React 19 对应同步任务或并发任务,最终会调用:
performWorkOnRootViaSchedulerTask(root)

这一步触发新的 render 阶段。


四、lane:优先级模型

React 19 引入 lane 来控制更新优先级:

  • 每个 update 对应一个 lane,例如:
SyncLane          // 同步更新,立即执行
InputContinuousLane
DefaultLane
TransitionLane    // 并发过渡更新
  • 同一个 Fiber 可以同时有多个 lane,表示多次更新需要调和
  • 调度器会根据 lane 决定:
render 阶段是否同步
是否可以被中断
  • React 会在 ensureRootIsScheduled 中根据 lane 调度微任务或 Scheduler callback

五、Fiber 复用与 workInProgress 创建

在 render 阶段,React 会为每个更新创建 workInProgress Fiber:

  1. 如果 current Fiber 存在,调用:
createWorkInProgress(current, pendingProps)
  1. 如果是初次渲染,直接创建新的 Fiber

workInProgress Fiber 会复用旧 Fiber 的:

  • Hook 链表
  • stateNode(DOM 或 class 实例)

更新阶段的 render 阶段,workInProgress Fiber 会计算新的 state,并生成新的子 Fiber 链表。


六、更新链路概览

  1. dispatchAction:setState 调用产生 update,并加入 updateQueue
  2. scheduleUpdateOnFiber:调度 Fiber,标记 lane,确保 root 调度
  3. Scheduler 调度:调用 performWorkOnRootViaSchedulerTask
  4. render 阶段
  • beginWork → 执行函数组件 / HostComponent / HostText
  • renderWithHooks → 计算新的 Hook 状态
  • reconcileChildren → 生成新的子 Fiber tree
  • completeWork → 向上归并,创建/准备 DOM
  1. commit 阶段
  • beforeMutation / mutation / layout
  • passive effect 异步 flush
  1. Fiber 状态切换
root.current = finishedWork
  1. 下一轮更新继续调度 Fiber,lane 优先级保证高优先级任务先执行

七、并发更新下的行为

在 concurrent render 模式下:

  • render 阶段可以被中断,workInProgress 暂存
  • Scheduler 可以中断低优先级更新,让高优先级更新先执行
  • lane 模型保证不同优先级的 update 不会混乱
  • commit 阶段仍然不可中断

八、结论

  1. dispatchAction 是状态更新的第一步,直接关联 Fiber 和 updateQueue
  2. updateQueue 保存 Hook 状态更新和 pending update
  3. scheduleUpdateOnFiber 将 Fiber 加入 root schedule,触发新的 render
  4. lane 决定更新优先级、可中断性和调度顺序
  5. workInProgress Fiber 复用 current Fiber,实现状态隔离和并发安全
  6. render → completeWork → commitRoot → passive effect 构成完整的更新链路
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐