一天一个react18.2.0 api——createRoot

153 阅读2分钟

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对象。

本篇分析就到这个地方。