想想react会怎么做(4)之 createContainer和updateContainer

53 阅读1分钟

前言

我们从第2节了解到react的入口文件中的执行的ReactDOM.createRoot( document.querySelector('#root') ).render()方法主要逻辑就是createContainer和updateContainer,整体流程为:

  1. ReactDOM.createRoot

    1. createContainer创建FiberRoot
    2. 返回ReactDOMRoot实例,属性_internalRoot为FiberRoot
  2. render

    1. 调用updateContainer方法,入参为_internalRoot和children(ReactNodeList)

然后我们从第3节也学习到了FiberRoot和Fiber的基本数据结构

所以我们这节就来介绍一下createContainer和updateContainer方法

createContainer

export function createContainer(
  containerInfo: Container,
  // ...
) {
  return createFiberRoot(
    containerInfo,
    // ... 
  );
}

export function createFiberRoot(
  containerInfo: Container,
  // ... 
): FiberRoot {
  // 创建FiberRoot
  const root: FiberRoot = (new FiberRootNode(
    containerInfo,
    tag,
    hydrate,
    identifierPrefix,
    onUncaughtError,
    onCaughtError,
    onRecoverableError,
    formState,
  ): any);

  // 创建RootFiber,其实就是一个Tag为HostRoot(3)的Fiber
  const uninitializedFiber = createHostRootFiber(
    tag,
    isStrictMode,
    concurrentUpdatesByDefaultOverride,
  );
  // 建立FiberRoot和RootFiber的关联
  root.current = uninitializedFiber;
  uninitializedFiber.stateNode = root;

  // 给RootFiber初始化它的更新队列
  initializeUpdateQueue(uninitializedFiber);

  // 返回FiberRoot
  return root;
}

// 初始化更新队列方法
export function initializeUpdateQueue<State>(fiber: Fiber): void {
  const queue: UpdateQueue<State> = {
    baseState: fiber.memoizedState,
    firstBaseUpdate: null,
    lastBaseUpdate: null,
    shared: {
      pending: null,
      lanes: NoLanes,
      hiddenCallbacks: null,
    },
    callbacks: null,
  };
  // 给fiber的updateQueue初始化一个更新队列
  fiber.updateQueue = queue;
}

updateContainer

export function updateContainer(
  // render的入参,<App /> (ReactElement)
  element: ReactNodeList,
  // fiberRoot
  container: OpaqueRoot,
  parentComponent: ?React$Component<any, any>,
  callback: ?Function,
): Lane {
  // rootFiber
  const current = container.current;
  // 创建一个优先级
  const lane = requestUpdateLane(current);
  // updateContainer实现
  updateContainerImpl(
    current,
    lane,
    element,
    container,
    parentComponent,
    callback,
  );
  return lane;
}

function updateContainerImpl(
  rootFiber: Fiber,
  lane: Lane,
  element: ReactNodeList,
  // fiberRoot
  container: OpaqueRoot,
  parentComponent: ?React$Component<any, any>,
  callback: ?Function,
): void {

  // ...

  // 根据lane创建一个更新
  const update = createUpdate(lane);
  // 将element放入更新(也就是创建一个渲染element的更新)
  update.payload = {element};

  // 将这个更新放入更新队列
  const root = enqueueUpdate(rootFiber, update, lane);
  if (root !== null) {
    // 开始根据优先级调度rootFiber
    scheduleUpdateOnFiber(root, rootFiber, lane);
  }
}

那边现在肯定你又会有问题了:

  1. 这里的lane是什么意思,它的作用是什么?
  2. 这里react的更新和更新队列是怎么设计的,它的作用是什么?
  3. react是怎么调度任务的?

让我们下回分解~