想想react会怎么做(2)之 ReactDOM

29 阅读1分钟

前言

我们都知道,一般react项目根目录的入口文件中都有以下这段代码

其中就使用到了ReactDOM的createRoot方法以及其创建出的实例的render方法

代码逻辑就是获取根节点,然后将App组件渲染到根节点下

import ReactDOM from 'react-dom/client';

import { App } from './App.jsx'

ReactDOM.createRoot( 
  document.querySelector('#root')
).render(<App />)

那么ReactDom中的各方法是怎么实现的呢?我们一步步来解读

createRoot

目录在packages/react-dom/src/client/ReactDOMRoot.js

createRoot核心逻辑

  1. 通过createContainer方法将传入的container转换为FiberRoot

  2. 通过FiberRoot生成ReactDOMRoot实例

    1. ReactDOMRoot实例上会继承原型上render方法
    2. ReactDOMRoot.prototype.render的核心步骤就是调用updateContainer方法
  3. 将ReactDOMRoot实例return出去

import {
  createContainer
} from 'react-reconciler/src/ReactFiberReconciler';

export type RootType = {
  render(children: ReactNodeList): void,
  unmount(): void,
  _internalRoot: FiberRoot | null,
};

export function createRoot(
  container: Element | Document | DocumentFragment
):RootType {
	const root = createContainer(container);
    return new ReactDOMRoot(root);
}

function ReactDOMRoot(internalRoot: FiberRoot) {
  this._internalRoot = internalRoot;
}

render

import {
  updateContainer,
} from 'react-reconciler/src/ReactFiberReconciler';

ReactDOMRoot.prototype.render = function (
  children: ReactNodeList
): void {
  const root = this._internalRoot;
  if (root === null) {
    throw new Error('Cannot update an unmounted root.');
  }
  updateContainer(children, root, null, null);
};

这个ReactDOMRoot实例的原型上有render方法,入参为一个ReactNodeList类型的children,其中主要逻辑就是调用updateContainer方法,入参是通过createContainer创建的FiberRoot实例和children(ReactNodeList)

ReactNodeList

ReactNodeList类型是什么呢?

// ReactNodeList类型声明
export type ReactNodeList = ReactEmpty | React$Node;

export type ReactEmpty = null | void | boolean;

export type ReactNode =
  | React$Element<any>
  | ReactPortal
  | ReactText
  | ReactFragment
  | ReactProvider<any>
  | ReactConsumer<any>;

可以看到,其实ReactNodeList也就包含了ReactElement,这就是和上节的jsx方法最后的返回值对上了

疑问

我们发现这个地方的关键逻辑createContainer,updateContainer都是来自react的另外一个包,叫做react-reconciler

而你肯定也会有疑问:createContainer,updateContainer中的具体逻辑是什么?FiberRoot是什么?

其实这些逻辑的答案都在react-reconciler之中,让我们下回分解