🔥🔥🔥 React18 源码学习 - 容器的挂载

前言

本文的React代码版本为18.2.0

可调试的代码仓库为:GitHub - yyyao-hh/react-debug at master-pure

当我们初次学习React时,第一个接触的API往往是ReactDOM.render。这个方法是React应用与浏览器 DOM连接的桥梁,也是整个应用渲染的起点。理解它的实现原理能为后续理解组件生命周期、虚拟DOM和协调算法打下坚实基础。

ReactDOM.render 的基本调用

在React应用中,我们通常这样使用ReactDOM.render:

  • React17及之前:首先获取一个DOM容器,然后将应用进行挂载。
javascript 复制代码
/* src/index.js */

import ReactDOM from 'react-dom';
import App from './App';

const root = document.getElementById('root');
ReactDOM.render(<App />, root);
  • React18开始:首先需要创建一个能够支持并发特性的root对象,然后将应用进行挂载。
javascript 复制代码
/* src/index.js */

import * as ReactDOM from 'react-dom/client';
import App from './App';

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

ReactDOM.createRoot的作用便是创建React根节点:作为一个长期存在的、用于管理该容器内整个React树的控制中心。接下来将围绕这个函数进行深入分析!

ReactDOM.render在React18中已被标记为"废弃"(legacy)。它创建的根节点运行在遗留模式(Legacy Mode)下,其渲染过程是同步、不可中断的。

而ReactDOM.createRoot创建的根节点,则默认启用了并发模式(Concurrent Mode)。它允许React在准备渲染更新时进行中断、暂停和恢复,将主线程的控制权交还给浏览器以优先处理高优先级的用户交互(如输入、动画),从而带来更流畅的用户体验。

ReactDOM.createRoot:构建根容器

我们现在开始深入了解下ReactDOM.createRoot这个函数:

javascript 复制代码
/* src/index.js */

import ReactDOM from 'react-dom';

const root = ReactDOM.createRoot(document.getElementById('root'));

在深入阅读源码后我们会了解到,ReactDOM.createRoot通过层层调用最终停在了某个createRoot方法中,这时的createRoot主要做了三件事:

  1. createContainer: 创建了根容器对象FiberRoot
  2. listenToAllSupportedEvents: 代理了所有事件,这是React合成事件系统的基石
  3. new ReactDOMRoot: 创建ReactDOMRoot实例并返回。该实例对外暴露了render和unmount方法
scss 复制代码
/* src/react/packages/react-dom/client.js */
export function createRoot(...): RootType {
  return createRootImpl(...);
}

/* src/react/packages/react-dom/src/client/ReactDOM.js */
function createRoot(...): RootType {
  return createRootImpl(...);
}

/* src/react/packages/react-dom/src/client/ReactDOMRoot.js */
export function createRoot(...): RootType {
  // 1. 创建容器对象 FiberRoot
  const root = createContainer(...);

  // 2. 代理所有事件
  listenToAllSupportedEvents(rootContainerElement);

  // 3. 返回公开的根对象
  return new ReactDOMRoot(root);
}

然后我们看到createContainer函数中又继续调用了createFiberRoot函数。在这个函数的内部依旧做了三件比较关键的事:

  1. 创建 FiberRootNode
  2. 创建 RootFiberNode
  3. 进行关联,二者通过.current和.stateNode互相引用,形成闭环:
arduino 复制代码
/* src/react/packages/react-reconciler/src/ReactFiberReconciler.old.js */
export function createContainer(...): OpaqueRoot {
  return createFiberRoot(...);
}

/* src/react/packages/react-reconciler/src/ReactFiberRoot.old.js */
export function createFiberRoot(...): FiberRoot {
  // 1. 创建 FiberRoot
  const root: FiberRoot = (new FiberRootNode(...));

  // 2. 创建 RootFiber
  const uninitializedFiber = createHostRootFiber(...);
  
  // 3. 将二者进行关联
  root.current = uninitializedFiber;
  uninitializedFiber.stateNode = root;

  return root;
}

看到这里大家肯定对这新出现的结构一脸懵 o((⊙﹏⊙))o

  • FiberRootNode :Fiber树的容器,它代表了整个React应用的根节点,与实际的DOM容器(例如div#root)相关联。每个React应用通常只有一个FiberRoot
  • RootFiberNode :Fiber树的根节点,即HostRoot。它是Fiber树结构的起点,其子节点就是应用顶层组件(例如<App />)

最后顺便看一下用于生成RootFiber的函数:createHostRootFiber。它通过调用函数createFiber并传入HostRoot参数,生成了一个代表根节点的Fiber。

这里还有很多Fiber类型,会在Fiber相关的章节详细讲到

javascript 复制代码
/* src/react/packages/react-reconciler/src/ReactWorkTags.js */
export const FunctionComponent = 0; // 函数组件
export const ClassComponent = 1;    // 类组件
export const HostRoot = 3;          // 根节点

/* src/react/packages/react-reconciler/src/ReactFiber.old.js */
export function createHostRootFiber(...): Fiber {
  return createFiber(HostRoot, null, null, mode);
}

const createFiber = function(...): Fiber {
  return new FiberNode(...);
}

总结

本文从宏观角度解析了ReactDOM.createRoot如何为React应用初始化容器、创建核心数据结构,并最终准备好渲染的舞台。理解这一过程是掌握React并发渲染模型(Concurrent Mode)的基础。

下一章我们将学习另一个重要的数据结构:Fiber

相关推荐
嘎嘎风3 小时前
MiniMind 学习笔记之 21 训练细节:数据、分词器、断点续训
gpt·源码阅读
Java后端的Ai之路3 小时前
07React_Props验证器
人工智能·python·react.js·架构·fastapi
RobinXYuan4 小时前
【Kafka 源码手记】01 从消息队列到 Event Streaming
kafka·源码阅读
Aolith4 小时前
从收藏到错题本,我在 React 全栈项目里实现了一套复习系统
mongodb·react.js·全栈
一木 之林6 小时前
Agent智能体学习总结:从一次调用到模型自主规划、工具调用与 ReAct 循环的项目实战-6/6
前端·人工智能·学习·react.js
song5011 天前
React Native for OpenHarmony 实战:三方库 react-native-parallax-scroll-view 的鸿蒙化适配指南
分布式·react native·react.js·transformer·harmonyos
song5011 天前
React Native for OpenHarmony 实战:三方库 react-native-ratings 的鸿蒙化适配指南
javascript·react native·react.js·分类·harmonyos
晓得迷路了1 天前
栗子前端技术周刊第 149 期 - Vite+ 1.0、Preact 11、Next.js 16.4...
前端·javascript·react.js
song5011 天前
React Native for OpenHarmony 实战:三方库 react-native-popup-menu 的鸿蒙化适配指南
css·深度学习·react native·react.js·transformer·harmonyos
haluhalu.1 天前
Agent = LLM + 上下文 + 工具(含观察 / 动作空间、ReAct 循环)
前端·javascript·人工智能·python·react.js·机器学习·个人开发