概述
在官方文档中有三种模式
-
legacy 模式:
ReactDOM.render(<App />, rootNode)
-
blocking 模式:
ReactDOM.createBlockingRoot(rootNode).render(<App />)
-
concurrent 模式:
ReactDOM.createRoot(rootNode).render(<App />)
为啥会有三种模式,React 官方文档也给出了相关说明,咱们从源码的上看看三者有何区别
ReactDOM.createBlockingRoot VS ReactDOM.createRoot
ReactDOM.createBlockingRoot
export function createBlockingRoot(container: Container, options?: RootOptions): RootType {
return new ReactDOMBlockingRoot(container, BlockingRoot, options);
}
function ReactDOMBlockingRoot(container: Container, tag: RootTag, options: void | RootOptions) {
this._internalRoot = createRootImpl(container, tag, options);
}
ReactDOM.createRoot
export function createRoot(container: Container, options?: RootOptions): RootType {
return new ReactDOMRoot(container, options);
}
function ReactDOMRoot(container: Container, options: void | RootOptions) {
this._internalRoot = createRootImpl(container, ConcurrentRoot, options);
}
可以从代码中看出,二者都返回一个对象,这个对象中有一个 _internalRoot
属性,属性值为 createRootImpl
的返回值,并且传入 createRootImpl
的第二个参数是不同的,一个是 BlockingRoot
一个是 ConcurrentRoot
。在源码中还可以看见 render
方法
ReactDOMRoot.prototype.render = ReactDOMBlockingRoot.prototype.render = function (children: ReactNodeList): void {
const root = this._internalRoot;
updateContainer(children, root, null, null);
};
也就是说两者最终都调用了 updateContainer
方法
ReactDOM.render
export function render(element: React$Element<any>, container: Container, callback: ?Function) {
return legacyRenderSubtreeIntoContainer(null, element, container, false, callback);
}
function legacyRenderSubtreeIntoContainer(
parentComponent: ?React$Component<any, any>,
children: ReactNodeList,
container: Container,
forceHydrate: boolean,
callback: ?Function
) {
let root: RootType = (container._reactRootContainer: any);
let fiberRoot;
if (!root) {
// Initial mount
root = container._reactRootContainer = legacyCreateRootFromDOMContainer(container, forceHydrate);
fiberRoot = root._internalRoot;
if (typeof callback === 'function') {
const originalCallback = callback;
callback = function () {
const instance = getPublicRootInstance(fiberRoot);
originalCallback.call(instance);
};
}
// Initial mount should not be batched.
unbatchedUpdates(() => {
updateContainer(children, fiberRoot, parentComponent, callback);
});
} else {
fiberRoot = root._internalRoot;
if (typeof callback === 'function') {
const originalCallback = callback;
callback = function () {
const instance = getPublicRootInstance(fiberRoot);
originalCallback.call(instance);
};
}
// Update
updateContainer(children, fiberRoot, parentComponent, callback);
}
return getPublicRootInstance(fiberRoot);
}
// legacyCreateRootFromDOMContainer
function legacyCreateRootFromDOMContainer(container: Container, forceHydrate: boolean): RootType {
const shouldHydrate = forceHydrate || shouldHydrateDueToLegacyHeuristic(container);
// First clear any existing content.
if (!shouldHydrate) {
let rootSibling;
while ((rootSibling = container.lastChild)) {
container.removeChild(rootSibling);
}
}
return createLegacyRoot(container, shouldHydrate ? {hydrate: true} : undefined);
}
// createLegacyRoot
export function createLegacyRoot(container: Container, options?: RootOptions): RootType {
return new ReactDOMBlockingRoot(container, LegacyRoot, options);
}
从代码中可以看到,render -> legacyRenderSubtreeIntoContainer -> legacyCreateRootFromDOMContainer -> createLegacyRoot -> ReactDOMBlockingRoot
,即 render
中 root
是 ReactDOMBlockingRoot
的实例,但是这里的参数是 LegacyRoot
。并且在 legacyRenderSubtreeIntoContainer
函数中也调用了 updateContainer
网友评论