Skip to content

第 9 章第 1 节:并发模式的开启

React 的并发模式(Concurrent Mode)是其现代架构的核心,它允许 React 在渲染过程中中断、暂停和恢复工作,从而极大地提高了应用的响应性和用户体验。与早期版本不同,并发模式不是一个可以随意切换的“开关”,而是通过使用新的 Root API 来选择加入(opt-in)的。

这个新的 API 就是 ReactDOM.createRoot

1. createRoot:并发的入口

当你使用 ReactDOM.createRoot 来初始化你的 React 应用时,你就已经将整个应用置于并发模式下运行。

javascript
// main.js
import { createRoot } from 'react-dom/client';

const container = document.getElementById('root');
const root = createRoot(container);
root.render(<App />);

让我们深入源码,看看 createRoot 究竟做了什么来开启并发模式。

javascript
// packages/react-dom/src/client/ReactDOM.js

function createRoot(container, options) {
  // 1. 验证容器是否有效
  if (!isValidContainer(container)) {
    throw new Error('Target container is not a DOM element.');
  }

  // ... 省略部分选项处理 ...

  // 2. 创建 FiberRootNode (核心)
  const root = createContainer(
    container,          // DOM 容器节点
    ConcurrentRoot,     // 根节点类型 (并发模式)
    null,               // hydrationCallbacks
    isStrictMode,       // 是否严格模式
    // ... 其他参数
  );

  // 3. 标记 DOM 容器,并设置事件监听
  markContainerAsRoot(root.current, container);
  listenToAllSupportedEvents(container);

  // 4. 返回一个 ReactDOMRoot 实例
  return new ReactDOMRoot(root);
}

从源码中可以清晰地看到,createRoot 的核心是调用了 createContainer 函数,并且在调用时传递了一个至关重要的参数:ConcurrentRoot

2. ConcurrentRoot:并发模式的标志

ConcurrentRoot 是一个常量,它定义在 ReactRootTags.js 文件中,用来标记 FiberRoot 的类型。

javascript
// packages/shared/ReactRootTags.js

export type RootTag = 0 | 1 | 2;

export const LegacyRoot = 0;
export const ConcurrentRoot = 1;
export const BatchedRoot = 2; // 在 React 18 中已不推荐使用

createContainer 函数接收到 ConcurrentRoot 这个 tag 时,它会创建一个 FiberRootNode 实例,并将其 tag 属性设置为 ConcurrentRoot。这个 tag 会在整个 React 的工作循环中被频繁检查,以决定采用何种渲染行为。

  • 如果是 ConcurrentRoot:React 会启用其所有的并发特性,例如时间分片(Time Slicing)、可中断渲染(Interruptible Rendering)以及基于 useTransition 的优先级调度。
  • 如果是 LegacyRoot:React 会以传统的、同步的、不可中断的方式进行渲染,这与 React 17 及之前的行为一致。ReactDOM.render API 创建的就是 LegacyRoot

3. createContainercreateFiberRoot

createContainer 进一步调用 createFiberRoot,后者负责真正地实例化 FiberRootNodeHostRootFiber(根 Fiber 节点)。

javascript
// packages/react-reconciler/src/ReactFiberRoot.js

export function createFiberRoot(
  containerInfo: Container,
  tag: RootTag, // 在这里接收到 ConcurrentRoot
  hydrate: boolean,
  // ... 其他参数
): FiberRoot {
  // 1. 创建 FiberRootNode 实例
  const root: FiberRoot = new FiberRootNode(containerInfo, tag, hydrate, ...);

  // 2. 创建 HostRootFiber
  const uninitializedFiber = createHostRootFiber(tag, ...);

  // 3. 建立关联
  root.current = uninitializedFiber;
  uninitializedFiber.stateNode = root;

  // ...

  return root;
}

createFiberRoot 的逻辑非常清晰:

  1. 创建 FiberRootNode:它将 ConcurrentRoot 这个 tag 保存到新创建的 FiberRootNode 实例上。这个实例是整个应用的“大脑”,掌管着所有更新和状态。
  2. 创建 HostRootFiber:创建根 Fiber 节点,它同样被标记为 ConcurrentRoot 模式。
  3. 建立循环引用:将 FiberRootNodeHostRootFiber 相互关联,构成 React 内部工作的基础结构。

4. 总结

并发模式的开启并非通过一个复杂的配置或开关,而是通过选择使用 ReactDOM.createRoot 这个入口 API 来实现的。这一行为在设计上是明确且强制的,确保了所有使用新 API 的应用都能享受到并发带来的好处。

其核心原理可以总结为:

  1. createRoot 调用 createContainer
  2. createContainer 传入 ConcurrentRoot 标志。
  3. createFiberRoot 基于 ConcurrentRoot 标志创建 FiberRootNodeHostRootFiber
  4. React 在后续的渲染和更新流程中,通过检查 FiberRootNode 上的 tag 来判断是否启用并发渲染路径。

通过这种方式,React 团队巧妙地引导开发者迁移到新的并发架构上,为构建更流畅、更具响应性的现代 Web 应用铺平了道路。

Last updated: