前言
我们都知道,一般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核心逻辑
-
通过createContainer方法将传入的container转换为FiberRoot
-
通过FiberRoot生成ReactDOMRoot实例
- ReactDOMRoot实例上会继承原型上render方法
- ReactDOMRoot.prototype.render的核心步骤就是调用updateContainer方法
-
将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之中,让我们下回分解