Jinuss's blog Jinuss's blog
首页
  • 源码合集

    • Leaflet源码分析
    • Openlayers源码合集
    • vue3源码
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

东流

Web、WebGIS技术博客
首页
  • 源码合集

    • Leaflet源码分析
    • Openlayers源码合集
    • vue3源码
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 《React源码》笔记
  • ReactDOM
东流
2026-01-19
目录

createRoot解析

React 18+ 中 createRoot 函数的源码实现:

function createRoot(container, options) {
  if (!isValidContainer(container)) throw Error(formatProdErrorMessage(299));
  var isStrictMode = !1,
    identifierPrefix = "",
    onUncaughtError = defaultOnUncaughtError,
    onCaughtError = defaultOnCaughtError,
    onRecoverableError = defaultOnRecoverableError;
  null !== options &&
    void 0 !== options &&
    (!0 === options.unstable_strictMode && (isStrictMode = !0),
    void 0 !== options.identifierPrefix &&
      (identifierPrefix = options.identifierPrefix),
    void 0 !== options.onUncaughtError &&
      (onUncaughtError = options.onUncaughtError),
    void 0 !== options.onCaughtError && (onCaughtError = options.onCaughtError),
    void 0 !== options.onRecoverableError &&
      (onRecoverableError = options.onRecoverableError));
  
  // 创建Fiber根节点
  options = createFiberRoot(
    container,
    1,
    !1,
    null,
    null,
    isStrictMode,
    identifierPrefix,
    null,
    onUncaughtError,
    onCaughtError,
    onRecoverableError,
    defaultOnDefaultTransitionIndicator
  );
  // 标记根节点
  container[internalContainerInstanceKey] = options.current;
  
  // 绑定元素的事件监听
  listenToAllSupportedEvents(container);
  
  return new ReactDOMRoot(options);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

# 逐步解析

# 1. 容器有效性检查

if (!isValidContainer(container)) {
  throw new Error('createRoot(...): Target container is not a DOM element.');
}
1
2
3

isValidContainer 函数检查容器是否有效:

  • 必须是 DOM 元素节点 (ELEMENT_NODE = 1)
  • 或者是文档节点 (DOCUMENT_NODE = 9)
  • 或者是文档片段节点 (DOCUMENT_FRAGMENT_NODE = 11)
  • 或者是注释节点 (COMMENT_NODE = 8) - React 18 新支持

# 2. 配置选项解析

# 支持的 options:

选项 类型 作用
unstable_strictMode boolean 启用严格模式(React 18 中已稳定但命名暂未变)
identifierPrefix string SSR 时生成 ID 的前缀,避免多个应用冲突
onRecoverableError function 错误边界未捕获错误时的回调
transitionCallbacks object Transition 相关回调(React 19 中已变更)

# 4. 创建 Fiber 根节点

var root = createFiberRoot(
  container,           // DOM 容器
  ConcurrentRoot,      // 模式:并发模式 1
  null,                // 初始 children
  isStrictMode,        // 是否严格模式
  concurrentUpdatesByDefaultOverride, // 并发更新默认覆盖
  identifierPrefix,    // ID 前缀
  onRecoverableError   // 可恢复错误处理
);
1
2
3
4
5
6
7
8
9

createFiberRoot 的作用:

  1. 创建 FiberRootNode(全局根节点)
  2. 创建 HostRootFiber(Fiber树的根)
  3. 初始化更新队列
  4. 设置各种内部属性

# 5. 标记容器

markContainerAsRoot(root.current, container);
1

建立容器与 Fiber 根的关联:

// 简化实现:
function markContainerAsRoot(hostRoot, container) {
  node[internalContainerInstanceKey] = hostRoot;
}
1
2
3
4

# 6. 确定事件监听目标

var rootContainerElement = container.nodeType === COMMENT_NODE 
  ? container.parentNode 
  : container;
1
2
3

重要:React 18 支持注释节点作为容器(用于 SSR hydration):

<!-- 客户端渲染前 -->
<div id="root">
  <!--$-->
</div>

<!-- 服务器渲染后 -->
<div id="root">
  <!--$-->
  <div>服务端渲染的内容</div>
  <!--/$-->
</div>
1
2
3
4
5
6
7
8
9
10
11

# 7. 事件系统初始化

listenToAllSupportedEvents(rootContainerElement);
1

这是 React 事件系统的核心,实现事件委托:

function listenToAllSupportedEvents(rootContainerElement) {
  // 遍历所有支持的事件类型
  allNativeEvents.forEach(domEventName => {
    // 非委托事件(如 scroll、load 等)
    if (!nonDelegatedEvents.has(domEventName)) {
      // 在捕获阶段监听
      listenToNativeEvent(
        domEventName, 
        false,  // capture
        rootContainerElement
      );
    }
    // 在冒泡阶段监听
    listenToNativeEvent(
      domEventName, 
        true,  // bubble
        rootContainerElement
    );
  });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

事件系统特点:

  • 所有事件委托到根容器
  • 提高性能,减少内存占用
  • 统一处理浏览器兼容性

# 与 React 16 的差异

# React 16 的 ReactDOM.render:

ReactDOM.render(<App />, document.getElementById('root'));
// 创建 LegacyRoot(传统模式)
1
2

# React 17+ 的 createRoot:

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
// 创建 ConcurrentRoot(并发模式)
1
2
3

# 核心差异对比

特性 Legacy Mode Concurrent Mode
Fiber 根类型 LegacyRoot (0) ConcurrentRoot (1)
渲染模式 同步阻塞 可中断并发
事件处理 每个元素独立监听 根容器事件委托
容器类型 仅 DOM 元素 DOM 元素或注释节点
SSR Hydration 全有或全无 渐进式 hydration

# 完整的初始化流程

// 用户调用
const root = createRoot(document.getElementById('app'), {
  identifierPrefix: 'my-app-',
  onRecoverableError: (error) => {
    console.error('React 错误:', error);
  }
});

// 内部执行流程:
1. 检查容器有效性
2. 开发环境警告
3. 解析配置选项
4. 创建 `FiberRootNode`
   - `tag`: `ConcurrentRoot`
   - `containerInfo`: DOM 容器
   - `pendingChildren`: `null`
5. 创建 `HostRootFiber`
   - `tag`: `HostRoot`
   - `stateNode`: `FiberRootNode`
6. 关联容器与根节点
7. 设置事件委托
8. 返回包装对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 错误边界和可恢复错误

// 用户可提供自定义错误处理
createRoot(container, {
  onRecoverableError: (error, errorInfo) => {
    // 报告到监控系统
    reportToErrorMonitoring(error, {
      componentStack: errorInfo.componentStack
    });
  }
});
1
2
3
4
5
6
7
8
9

# SSR Hydration 的特殊处理

// 服务器渲染时
const html = ReactDOMServer.renderToString(<App />);

// 客户端
const root = createRoot(container, {
  // 如果服务器渲染时用了标识符前缀
  identifierPrefix: 'myapp-'
});

// React 能正确匹配服务器和客户端节点
root.hydrate(<App />);
1
2
3
4
5
6
7
8
9
10
11

这个 createRoot 函数是 React 的入口点,它建立了整个 React 应用的基础架构,包括 Fiber 树、事件系统和并发调度机制。

编辑 (opens new window)
上次更新: 2026/01/20, 09:26:42
最近更新
01
updateContainerImpl方法更新容器
01-20
02
FiberNode详解
01-20
03
FiberRootNode属性介绍
01-19
更多文章>
Theme by Vdoing | Copyright © 2024-2026 东流 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式