Appearance
第 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.renderAPI 创建的就是LegacyRoot。
3. createContainer 和 createFiberRoot
createContainer 进一步调用 createFiberRoot,后者负责真正地实例化 FiberRootNode 和 HostRootFiber(根 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 的逻辑非常清晰:
- 创建
FiberRootNode:它将ConcurrentRoot这个tag保存到新创建的FiberRootNode实例上。这个实例是整个应用的“大脑”,掌管着所有更新和状态。 - 创建
HostRootFiber:创建根 Fiber 节点,它同样被标记为ConcurrentRoot模式。 - 建立循环引用:将
FiberRootNode和HostRootFiber相互关联,构成 React 内部工作的基础结构。
4. 总结
并发模式的开启并非通过一个复杂的配置或开关,而是通过选择使用 ReactDOM.createRoot 这个入口 API 来实现的。这一行为在设计上是明确且强制的,确保了所有使用新 API 的应用都能享受到并发带来的好处。
其核心原理可以总结为:
createRoot调用createContainer。createContainer传入ConcurrentRoot标志。createFiberRoot基于ConcurrentRoot标志创建FiberRootNode和HostRootFiber。- React 在后续的渲染和更新流程中,通过检查
FiberRootNode上的tag来判断是否启用并发渲染路径。
通过这种方式,React 团队巧妙地引导开发者迁移到新的并发架构上,为构建更流畅、更具响应性的现代 Web 应用铺平了道路。