React Fiber架构原理
约 1719 字大约 6 分钟
reactfiber
2025-07-24
概述
React Fiber 是 React 16 引入的全新协调引擎,它将渲染工作拆分为可中断的小单元,实现了时间分片(Time Slicing)和优先级调度。Fiber 架构是 React Concurrent Mode、Suspense、Transitions 等现代特性的基础。
从 Stack Reconciler 到 Fiber
Stack Reconciler 的问题:一旦开始渲染,必须同步递归处理整棵树,长时间占用主线程导致界面卡顿。Fiber 将工作拆分为可中断的增量单元,每个单元处理完可以检查是否需要让出控制权。
Fiber 节点结构
每个 React 元素对应一个 Fiber 节点,Fiber 节点通过链表连接形成 Fiber 树。
// Fiber 节点的简化结构
const fiberNode = {
// 类型信息
tag: 'FunctionComponent', // 组件类型标签
type: MyComponent, // 组件函数或类
key: null, // 列表 key
// 树结构(链表)
return: parentFiber, // 父节点
child: firstChildFiber, // 第一个子节点
sibling: nextSiblingFiber, // 下一个兄弟节点
// 状态
memoizedState: null, // Hooks 链表 / Class state
memoizedProps: null, // 上次渲染的 props
pendingProps: null, // 新的 props
// 副作用
flags: 'Update', // 副作用标志(Placement, Update, Deletion)
subtreeFlags: 0, // 子树副作用标志
// 双缓冲
alternate: workInProgressFiber, // 指向另一棵树中的对应节点
// 优先级
lanes: 0, // 优先级通道
};工作循环(Work Loop)
Fiber 的工作循环通过 performUnitOfWork 逐个处理 Fiber 节点。
// 简化的工作循环
function workLoop(deadline) {
let shouldYield = false;
while (nextUnitOfWork && !shouldYield) {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
shouldYield = deadline.timeRemaining() < 1; // 时间片耗尽
}
if (!nextUnitOfWork && wipRoot) {
commitRoot(); // 所有工作完成,提交到 DOM
}
requestIdleCallback(workLoop); // 注册下一次调度
}
function performUnitOfWork(fiber) {
// 1. beginWork: 处理当前节点,创建子 Fiber
const next = beginWork(fiber);
if (next) {
return next; // 有子节点,继续向下
}
// 2. completeWork: 没有子节点,完成当前节点
let current = fiber;
while (current) {
completeWork(current);
if (current.sibling) {
return current.sibling; // 有兄弟节点,处理兄弟
}
current = current.return; // 回到父节点
}
return null;
}遍历顺序
双缓冲(Double Buffering)
React 维护两棵 Fiber 树:current(当前屏幕显示)和 workInProgress(正在构建)。
// 双缓冲切换
function commitRoot() {
// 执行所有 DOM 操作
commitWork(wipRoot.child);
// 切换 current 指针
currentRoot = wipRoot;
wipRoot = null;
}两阶段处理:Render 与 Commit
Render Phase(可中断)
- 纯计算阶段,不产生可见的副作用
- 可以被高优先级任务打断
- 可能被执行多次(因此组件函数应该是纯函数)
Commit Phase(不可中断)
同步执行,分为三个子阶段:
function commitRoot() {
// 1. Before Mutation: 读取 DOM 状态
// - getSnapshotBeforeUpdate
// - useEffect 的清理函数调度
// 2. Mutation: 修改 DOM
// - 插入 (Placement)
// - 更新 (Update)
// - 删除 (Deletion)
// - ref 解绑
// 3. Layout: DOM 已更新,可安全读取
// - componentDidMount / componentDidUpdate
// - useLayoutEffect
// - ref 绑定
}优先级与 Lanes 模型
React 18 使用 Lanes 模型管理更新优先级。
// Lanes 定义(位运算,支持批量操作)
const SyncLane = 0b0000000000000000000000000000010;
const InputContinuousLane = 0b0000000000000000000000000001000;
const DefaultLane = 0b0000000000000000000000000100000;
const TransitionLane1 = 0b0000000000000000000001000000000;
const IdleLane = 0b0100000000000000000000000000000;
// 优先级从高到低
// SyncLane > InputContinuous > Default > Transition > IdleConcurrent 特性
Suspense
function App() {
return (
<Suspense fallback={<Loading />}>
<AsyncComponent />
</Suspense>
);
}
// Suspense 的工作原理:
// 1. 子组件抛出 Promise(throw promise)
// 2. Fiber 捕获 Promise,显示 fallback
// 3. Promise resolve 后重新渲染子组件Transitions
import { useState, useTransition } from 'react';
function SearchPage() {
const [query, setQuery] = useState('');
const [results, setResults] = useState([]);
const [isPending, startTransition] = useTransition();
function handleChange(e) {
setQuery(e.target.value); // 高优先级:立即更新输入框
startTransition(() => {
setResults(filterData(e.target.value)); // 低优先级:可中断的搜索
});
}
return (
<>
<input value={query} onChange={handleChange} />
{isPending ? <Spinner /> : <ResultList results={results} />}
</>
);
}自动批处理(React 18)
// React 18: 所有更新自动批处理
function handleClick() {
setCount(c => c + 1); // 不会立即重渲染
setFlag(f => !f); // 不会立即重渲染
// React 18 自动批处理,只重渲染一次
}
// 即使在 setTimeout 中也会批处理
setTimeout(() => {
setCount(c => c + 1);
setFlag(f => !f);
// React 18: 一次重渲染
// React 17: 两次重渲染
}, 1000);
// 如需强制同步更新
import { flushSync } from 'react-dom';
flushSync(() => setCount(c => c + 1)); // 立即重渲染
flushSync(() => setFlag(f => !f)); // 再次重渲染Hooks 在 Fiber 中的存储
// 这就是为什么 Hooks 不能在条件语句中使用
// Fiber 通过链表顺序索引对应 Hook
// Bad: 条件调用破坏链表顺序
function Bad({ condition }) {
const [a, setA] = useState(0); // Hook 1
if (condition) {
const [b, setB] = useState(0); // Hook 2(可能不存在!)
}
useEffect(() => {}); // Hook 2 或 3?顺序错乱!
}
// Good: 始终保持相同的调用顺序
function Good({ condition }) {
const [a, setA] = useState(0);
const [b, setB] = useState(0); // 始终调用
useEffect(() => {
if (condition) { /* 条件逻辑放在 Hook 内部 */ }
});
}总结
React Fiber 通过将渲染工作拆分为可中断的增量单元、引入优先级调度和双缓冲机制,彻底解决了 Stack Reconciler 时代长任务阻塞主线程的问题。Fiber 架构分为 Render(可中断,纯计算)和 Commit(不可中断,DOM 操作)两个阶段。Lanes 优先级模型使得用户交互可以打断低优先级的渲染工作。这一架构为 Concurrent Mode、Suspense、Transitions 等现代 React 特性提供了底层支撑。
贡献者
更新日志
2026/3/14 13:09
查看所有更新日志
9f6c2-feat: organize wiki content and refresh site setup于