跳到主要内容

React Fiber Root ? React Root Fiber ? who care !

在 React 中, Fiber Root 是 React 应用的核心入口点和协调器!是 React 应用的 核心管理中枢

注意区分
  • Fiber Root : React 内部管理整个应用根的数据结构,类型是 FiberRootNode,持有 DOM Root 的引用,同时维护整个应用的 Fiber 树、更新列队、渲染状态等核心信息
  • Root Fiber : Fiber 树中的第一个 Fiber 节点,对应 React 应用的顶层组件 ( 如 <App /> ),类型是 FiberNode
  • DOM Root : 真实 DOM 树的根容器(用户定义的节点),是 React 渲染结果的「挂载目标」

一、作用

1. 作为 React 应用的根节点

  • 作为 React 应用的根节点,是 React 组件树的顶层容器
  • 关联了 React 应用挂载的 DOM 节点,是 React 和 DOM 的桥梁
  • 保存了整个 React 应用的上下文信息
    • 包括当前的更新列队( pending updates )
    • 当前正在处理的 work-in-progress
    • 调度器相关信息(如 expiration time / lanes
    • 指向当前 Fiber 树的引用 ( current )

2.管理 Fiber 树

  • Fiber Root 持有整个应用的 Fiber 树(当前屏幕显示的 current 树和正在构建的 workInProgress 树)
  • 通过 Fiber 树, React 实现了 增量渲染 : 将渲染工作拆分为多个小任务,避免阻塞主线程

3.协调器(Reconciliation)的入口

  • 当组件状态/Props 变化时, Fiber Root 启动协调过程:
    • 遍历 Fiber 树,对比新旧虚拟 DOM (Diff 算法)
    • 收集需要更新的变更(增删改 DOM)
  • 协调过程可中断/恢复,保证页面流畅性

4. 调度更新(Scheduler)

  • Fiber Root 整合了 Scheduler 模块 ,决定更新任务的优先级:
    • 高优先级更新(如用户输入)可打断低优先级(如数据加载)
    • 通过时间切片( Time Slicing )和空闲时间( requestIdleCallback ) 性能优化

5.储存应用的全局状态与配置

Fiber Root 是 React 应用的「全局状态容器」,储存了影响整个应用运行的关键信息。

  • 更新列队pendingUpdates 储存待处理的更新,确保更新不会丢失,且能按优先级运行
  • 渲染状态 : 标记当前是否处于协调 ( isWorking ) 、是否处于提交阶段( isCommitting ),避免并发更新冲突
  • 全局配置 : 比如 hydrate (服务端渲染 hydration 模式 ) 、 strictMode (严格模式) 、 concurrentMode (并发模式)等配置,影响 React 的渲染行为
  • 上下文 : 全局 Context 的最新姿会储存子啊 Fiber Root 中,确保组件能获取到同一上下文
  • 错误边界 : 全局错误相关状态,用户捕获组件树中的错误并触发降级渲染

5. 维护副作用列表( Effect List )

  • 协调完后, Fiber Root 收集所有需要更新的副作用(如 DOM 操作)
  • 在提交阶段 ( Commit phase ) 一次执行这些副作用,更新真是 DOM

6.支持并发模式(Concurrent Mode)

  • Fiber Root 储存了多个优先级(lanes)的更新信息
  • 允许 React 暂停、恢复、中断或重排更新任务,实现时间切片 ( time slicing ) 和可中断渲染

二、创建 Fiber 根

信息
export function createFiberRoot(
containerInfo: Container,
tag: RootTag,
hydrate: boolean,
initialChildren: ReactNodeList,
hydrationCallbacks: null | SuspenseHydrationCallbacks,
isStrictMode: boolean,
// TODO: We have several of these arguments that are conceptually part of the
// TODO: 我们有几个这样的参数,从概念上来说它们是宿主配置的一部分,
// host config, but because they are passed in at runtime, we have to thread
// 但因为它们是在运行时传入的,所以我们必须通过根构造函数传递它们。
// them through the root constructor. Perhaps we should put them all into a
// 也许我们应该把它们都放到一个单独的类型中,比如由渲染器定义的 DynamicHostConfig。
// single type, like a DynamicHostConfig that is defined by the renderer.
identifierPrefix: string,
formState: ReactFormState<any, any> | null,
onUncaughtError: (
error: mixed,
// errorInfo: {+componentStack?: ?string},
errorInfo: { componentStack?: string },
) => void,
onCaughtError: (
error: mixed,
errorInfo: {
// +componentStack?: ?string,
componentStack?: string;
// +errorBoundary?: ?component(...props: any),
errorBoundary?: Components;
},
) => void,
onRecoverableError: (
error: mixed,
// errorInfo: {+componentStack?: ?string},
errorInfo: { componentStack?: string },
) => void,
onDefaultTransitionIndicator: () => void | (() => void),
transitionCallbacks: null | TransitionTracingCallbacks,
): FiberRoot {
const root: FiberRoot = new FiberRootNode(
containerInfo,
tag,
hydrate,
identifierPrefix,
onUncaughtError,
onCaughtError,
onRecoverableError,
onDefaultTransitionIndicator,
formState,
) as any;
if (enableSuspenseCallback) {
root.hydrationCallbacks = hydrationCallbacks;
}

if (enableTransitionTracing) {
root.transitionCallbacks = transitionCallbacks;
}

// Cyclic construction. This cheats the type system right now because
// stateNode is any.
// 循环构造。由于 stateNode 是 any,这会暂时绕过类型系统。
const uninitializedFiber = createHostRootFiber(tag, isStrictMode);
root.current = uninitializedFiber;
uninitializedFiber.stateNode = root;

const initialCache = createCache();
retainCache(initialCache);

// The pooledCache is a fresh cache instance that is used temporarily
// pooledCache 是一个新的缓存实例,临时用于渲染期间新挂载的边界。
// for newly mounted boundaries during a render. In general, the
// 通常情况下,pooledCache 会在渲染结束时从根节点清除:
// pooledCache is always cleared from the root at the end of a render:
// it is either released when render commits, or moved to an Offscreen
// 它要么在渲染提交时释放,要么在渲染挂起时移到 Offscreen 组件。
// component if rendering suspends. Because the lifetime of the pooled
// 因为 pooledCache 的生命周期不同于主 memoizedState.cache,所以必须单独保留。
// cache is distinct from the main memoizedState.cache, it must be
// retained separately.
root.pooledCache = initialCache;
retainCache(initialCache);
const initialState: RootState = {
element: initialChildren,
isDehydrated: hydrate,
cache: initialCache,
};
uninitializedFiber.memoizedState = initialState;

initializeUpdateQueue(uninitializedFiber);

return root;
}

三、工具

1. Fiber 根节点

信息
function FiberRootNode(
this: $FlowFixMe,
containerInfo: any,
tag,
hydrate: any,
identifierPrefix: any,
onUncaughtError: any,
onCaughtError: any,
onRecoverableError: any,
onDefaultTransitionIndicator: any,
formState: ReactFormState<any, any> | null,
) {
this.tag = disableLegacyMode ? ConcurrentRoot : tag;
this.containerInfo = containerInfo;
this.pendingChildren = null;
this.current = null;
this.pingCache = null;
this.timeoutHandle = noTimeout;
this.cancelPendingCommit = null;
this.context = null;
this.pendingContext = null;
this.next = null;
this.callbackNode = null;
this.callbackPriority = NoLane;
this.expirationTimes = createLaneMap(NoTimestamp);

this.pendingLanes = NoLanes;
this.suspendedLanes = NoLanes;
this.pingedLanes = NoLanes;
this.warmLanes = NoLanes;
this.expiredLanes = NoLanes;
if (enableDefaultTransitionIndicator) {
this.indicatorLanes = NoLanes;
}
this.errorRecoveryDisabledLanes = NoLanes;
this.shellSuspendCounter = 0;

this.entangledLanes = NoLanes;
this.entanglements = createLaneMap(NoLanes);

this.hiddenUpdates = createLaneMap(null);

this.identifierPrefix = identifierPrefix;
this.onUncaughtError = onUncaughtError;
this.onCaughtError = onCaughtError;
this.onRecoverableError = onRecoverableError;

if (enableDefaultTransitionIndicator) {
this.onDefaultTransitionIndicator = onDefaultTransitionIndicator;
this.pendingIndicator = null;
}

this.pooledCache = null;
this.pooledCacheLanes = NoLanes;

if (enableSuspenseCallback) {
this.hydrationCallbacks = null;
}

this.formState = formState;

if (enableViewTransition) {
this.transitionTypes = null;
}

if (enableGestureTransition) {
this.pendingGestures = null;
this.stoppingGestures = null;
this.gestureClone = null;
}

this.incompleteTransitions = new Map();
if (enableTransitionTracing) {
this.transitionCallbacks = null;
this.transitionLanes = createLaneMap(null);
}

if (enableProfilerTimer && enableProfilerCommitHooks) {
this.effectDuration = -0;
this.passiveEffectDuration = -0;
}

if (enableUpdaterTracking) {
this.memoizedUpdaters = new Set();
const pendingUpdatersLaneMap = (this.pendingUpdatersLaneMap = []);
for (let i = 0; i < TotalLanes; i++) {
pendingUpdatersLaneMap.push(new Set());
}
}

if (__DEV__) {
if (disableLegacyMode) {
// TODO: This varies by each renderer.
// 待办:这取决于每个渲染器而异。
this._debugRootType = hydrate ? 'hydrateRoot()' : 'createRoot()';
} else {
switch (tag) {
case ConcurrentRoot:
this._debugRootType = hydrate ? 'hydrateRoot()' : 'createRoot()';
break;
case LegacyRoot:
this._debugRootType = hydrate ? 'hydrate()' : 'render()';
break;
}
}
}
}