这里以React18的 Concurrent 并发模式作为基础
            
            
              js
              
              
            
          
          ReactDOM.createRoot(rootNode).render(<App />)
        createRoot被调用时发生了什么?
通过观察如下调用堆栈我们可以看到具体的过程:
执行的顺序从createRoot函数开始:
            
            
              js
              
              
            
          
          export function createRoot(
  container: Element | Document | DocumentFragment,
  options?: CreateRootOptions,
): RootType {
 
  // 省略掉一些处理createRoot options的逻辑
  
  const root = createContainer(
    container,
    ConcurrentRoot,
    null,
    isStrictMode,
    concurrentUpdatesByDefaultOverride,
    identifierPrefix,
    onUncaughtError,
    onCaughtError,
    onRecoverableError,
    transitionCallbacks,
  );
  return new ReactDOMRoot(root);
}
        可以看到在createRoot中会调用createContainer函数
            
            
              js
              
              
            
          
          function createContainer(containerInfo, tag, hydrationCallbacks, isStrictMode, concurrentUpdatesByDefaultOverride, identifierPrefix, onRecoverableError, transitionCallbacks) {
  var hydrate = false;
  var initialChildren = null;
  return createFiberRoot(containerInfo, tag, hydrate, initialChildren, hydrationCallbacks, isStrictMode, concurrentUpdatesByDefaultOverride, identifierPrefix, onRecoverableError);
}
        在createContainer函数 中会调用createFiberRoot
            
            
              js
              
              
            
          
          function createFiberRoot(containerInfo, tag, hydrate, initialChildren, hydrationCallbacks, isStrictMode, concurrentUpdatesByDefaultOverride, 
identifierPrefix, onRecoverableError, transitionCallbacks) {
  var root = new FiberRootNode(containerInfo, tag, hydrate, identifierPrefix, onRecoverableError);
  var uninitializedFiber = createHostRootFiber(tag, isStrictMode);
  root.current = uninitializedFiber;
  uninitializedFiber.stateNode = root;
  {
    var _initialState = {
      element: initialChildren,
      isDehydrated: hydrate,
      cache: null,
      // not enabled yet
      transitions: null,
      pendingSuspenseBoundaries: null
    };
    uninitializedFiber.memoizedState = _initialState;
  }
  initializeUpdateQueue(uninitializedFiber);
  return root;
}
        在createFiberRoot中会有如下过程
- 创建一个 FiberRootNode 的实例 
FiberRoot作为整个React应用的根节点 - 调用 
createHostRootFiber创建 一个尚未初始化的Fiber树 - 将 
FiberRoot.current设置为 HostRootFiber 将HostRootFiber的 stateNode 设置为 FiberRoot在二者之间建立联系 - 使用
initializeUpdateQueue初始化更新队列 - 返回根节点
 
ps:更新队列是一个内部的数据结构,用于管理组件的状态更新和上下文变化。它负责跟踪组件的更新,并将它们排队以便在合适的时机批量处理。
root.render()
上一步中createRoot创建的root对象prototype上的方法被调用:
            
            
              js
              
              
            
          
          ReactDOMHydrationRoot.prototype.render = ReactDOMRoot.prototype.render =
  function (children: ReactNodeList): void {
    const root = this._internalRoot;
    updateContainer(children, root, null, null);
  };
        进入updateContainer,updateContainer中处理了lane优先级相关信息,调用了updateContainerImpl进行后续处理,updateContainer相当于ReactDOM和reconciler的桥梁。
            
            
              js
              
              
            
          
          export function updateContainer(
  element: ReactNodeList,
  container: OpaqueRoot,
  parentComponent: ?React$Component<any, any>,
  callback: ?Function,
): Lane {
  const current = container.current;
  const lane = requestUpdateLane(current);
  updateContainerImpl(
    current,
    lane,
    element,
    container,
    parentComponent,
    callback,
  );
  return lane;
}
        updateContainerImpl:
- 调用 
enqueueUpdate函数将更新对象到根 Fiber 节点(rootFiber)上,并指定更新的优先级车道(lane) - 调用 
scheduleUpdateOnFiber函数将更新调度到根 Fiber 节点上,这将触发协调算法(reconciliation) 
            
            
              js
              
              
            
          
          function updateContainerImpl(
  rootFiber: Fiber,
  lane: Lane,
  element: ReactNodeList,
  container: OpaqueRoot,
  parentComponent: ?React$Component<any, any>,
  callback: ?Function,
): void {
  if (enableSchedulingProfiler) {
    markRenderScheduled(lane);
  }
  const context = getContextForSubtree(parentComponent);
  if (container.context === null) {
    container.context = context;
  } else {
    container.pendingContext = context;
  }
  const update = createUpdate(lane);
  update.payload = {element};
  callback = callback === undefined ? null : callback;
  
  if (callback !== null) {
    update.callback = callback;
  }
  const root = enqueueUpdate(rootFiber, update, lane);
  
  if (root !== null) {
    startUpdateTimerByLane(lane);
    // 进入reconciler
    scheduleUpdateOnFiber(root, rootFiber, lane);
    entangleTransitions(root, rootFiber, lane);
  }
}
        调用之后会进入调度以及协调的过程,相关内容在后续的文章中更新;
总结
本文解释了React应用启动入口ReactDOM.createRoot和root.render()方法的内部执行过程。