api使用介绍:
1,今天我们来介绍createRoot这个api。首先介绍一下这个api的使用方式。
const root = ReactDOM.createRoot(domNode, options?)
其中,root是createRoot返回的一个dom实例,domNode是一个dom节点,就是react要挂载的节点,options是创建根节点的配置项选项。
2,再介绍一下这个api的使用例子,这样就创建出来了一个跟react关联的根节点了。
const root = ReactDOM.createRoot(document.getElementById("root")).render(<App />, {});
createRoot源码解析
function createRoot(
container,
options?,
): RootType {
return createRootImpl(container, options);
}
这就是createRoot的源码,可以看到,核心就是创建一个rootImpl,然后返回一个rootType对象。
我们首先研究一下,最终返回的rootType是个什么结构,对最终的形态有一个直观的认识。
export type RootType = {
render(children: ReactNodeList): void,
unmount(): void,
_internalRoot: FiberRoot | null,
};
export type FiberRoot = {
...BaseFiberRootProperties,
...SuspenseCallbackOnlyFiberRootProperties,
...UpdaterTrackingOnlyFiberRootProperties,
...TransitionTracingOnlyFiberRootProperties,
};
可以看到,rootType是一个由render函数,unmount函数,还有_internalRoot组成的。render肯定就是用来渲染组件的,unmount肯定就是从节点上卸载用的。这里重点看看_internalRoot这个属性。
_internalRoot这个属性肯定就是把
const root = ReactDOM.createRoot(domNode, options?)
中的domNode处理之后,放到了FiberRoot里面。
可以看到,FiberRoot,又分了很多的属性,从名字上看,这些名字跟组件的渲染过程有关系,所以可以判断,这里的属性,是为了方便react渲染组件的时候,去拿配置变量的。
接下来我们看一下createRootImpl的具体过程,上源代码。
export function createRoot(
container,
options?,
): RootType {
if (!isValidContainer(container)) {
throw new Error('createRoot(...): Target container is not a DOM element.');
}
warnIfReactDOMContainerInDEV(container);
let isStrictMode = false;
let concurrentUpdatesByDefaultOverride = false;
let identifierPrefix = '';
let onRecoverableError = defaultOnRecoverableError;
let transitionCallbacks = null;
if (options !== null && options !== undefined) {
if (options.unstable_strictMode === true) {
isStrictMode = true;
}
if (
allowConcurrentByDefault &&
options.unstable_concurrentUpdatesByDefault === true
) {
concurrentUpdatesByDefaultOverride = true;
}
if (options.identifierPrefix !== undefined) {
identifierPrefix = options.identifierPrefix;
}
if (options.onRecoverableError !== undefined) {
onRecoverableError = options.onRecoverableError;
}
if (options.transitionCallbacks !== undefined) {
transitionCallbacks = options.transitionCallbacks;
}
}
const root = createContainer(
container,
ConcurrentRoot,
null,
isStrictMode,
concurrentUpdatesByDefaultOverride,
identifierPrefix,
onRecoverableError,
transitionCallbacks,
);
markContainerAsRoot(root.current, container);
const rootContainerElement: Document | Element | DocumentFragment =
container.nodeType === COMMENT_NODE
? (container.parentNode: any)
: container;
listenToAllSupportedEvents(rootContainerElement);
return new ReactDOMRoot(root);
}
核心就是两步,下面这两步
const root = createContainer(
container,
ConcurrentRoot,
null,
isStrictMode,
concurrentUpdatesByDefaultOverride,
identifierPrefix,
onRecoverableError,
transitionCallbacks,
);
return new ReactDOMRoot(root);
可以看到,一个是创建了一个container,一个就是把创建的container丢到ReactDOMRoot实例中,去创建一个ReactDOMRoot实例中,去创建一个RootType对象。
本篇分析就到这个地方。