React 元素和组件是从 Root 开始渲染的。那么我们 React Root 是如任何创建的呢?
两种 Root 根构造函数
ReactDOMRoot用与创建并发模式的构造函数ReactDOMBlockingRoot用与创建 blocking、legacy 模式的根
三种创建方法
三种创建方式代表了 React 三种 DOM 渲染方法,
- createRoot
- 实例化 ReactDOMRoot 类
- createBlockingRoot
- 实例化 ReactDOMBlockingRoot 类
- createLegacyRoot
- 实例化 ReactDOMBlockingRoot 类
其次 ReactDOMRoot 和 ReactDOMBlockingRoot 上面的挂载了相同的原型方法:
- render 用于渲染元素
- unmount 用于卸载元素
他们都是用于更新 updateContainer 更新容器, 更新容器的阶段不在 ReactDOM 中而是在接入 React 的协调阶段, 协调阶段与 Fiber 有直接关系
ReactDOMRoot 与 ReactDOMBlockingRoot 的区别
他们的内部都是调用 createRootImpl 使用给 _internalRoot 赋值。仅仅是传入的参数有差异
// ReactDOMRoot 是 ConcurrentRoot 模式,传入 ConcurrentRoot 根
this._internalRoot = createRootImpl(container, ConcurrentRoot, options);
// ReactDOMBlockingRoot
this._internalRoot = createRootImpl(container, tag, options);
createRootImpl 创建 Root 实现
// 实现创建 Root 的时候
const root = createContainer(container, tag, hydrate, hydrationCallbacks);
return root;
createContainer、updateContainer
创建容器和更新容器,不发生在 ReactDOM 中,而是发生在 React Reconiler 阶段。
特殊的传统模式渲染
传统的渲染的模式,直接调用 ReactDOM 的 render 方法。到了这里我们并不是直接就开始创建 React 的根。render 方法是直接调用了 legacyRenderSubtreeIntoContainer 方法,此方式事件将 react 元素渲染到指定的 dom 容器当中,它会有如下的操作:
- 读取
container._reactRootContainer,没有就调用legacyCreateRootFromDOMContainer函数创建一个container._reactRootContainer,然后走第一次渲染的流程,更新容器 - 如果读取到
container._reactRootContainer是有内容的,不在需要创建,直接更新。 - 回到
legacyCreateRootFromDOMContainer函数中,我们的确定我们的问题是在哪里创建了我们传统的根。 - 进入
legacyCreateRootFromDOMContainer函数, 直接调用createLegacyRoot。到这里就我们之前分析的三种模式中的传统模式结合起来了。
小结
- 在进入协调之前,我们需要确定用哪种模式渲染。当然一般是老传统模式。
- 传统的模式比较特殊,它是
ReactDOM的render方法渲染出来的。需要额外的初始化 root。然后走第一次渲染流程。 - 使用
createRootImpl实现了createContainer,进入了协调阶段
协调开始
在 React 协调开始吗createContainer 函数是在调用 createFiberRoot。要创建一个 Fiber 根。(注意 Fiber 根,与 Fiber 存在引用关系,但是他们不是同一个东西)。
其实就是实例化(具有:current属性)了一个 FiberRootNode 构造函数。然后处理 createHostRootFiber 实例(真的Fiber 根, 具有: stateNode 属性)的引用关系返回(其实这里还有很大的关系)。current 属性和 stateNode 属性相互应用。这个 fiber 数据结构中有巨大的作用。
到这开我们的根 root 就创阿金完毕了。然后就可以拿这个 root 去更新容器了。
总结
React 采用的链表的数据结构,根节点是我们渲染 React 的地方。React 创建根有三种模式。React 创建了根的内容,其实本质就是进入了协调阶段,生成 FiberRoot 和 host fiber。他们之间通过 current 属性和 stateNode 相互引用。