Skip to content
目录

updateContainer做了什么?

当react创建好RootFiber后,然后会调用updateContainer将应用渲染出来, 首先,计算expirationTime, 然后调用updateContainerAtExpirationTime 方法

typescript
export function updateContainer(
    element: ReactNodeList,
    container: OpaqueRoot,
    parentComponent: ?React$Component<any, any>,
    callback: ?Function,
): ExpirationTime {
  // root fiber
  const current = container.current;
  const currentTime = requestCurrentTime();
  // 计算expirationTime
  const expirationTime = computeExpirationForFiber(currentTime, current);
  return updateContainerAtExpirationTime(
      element,
      container,
      parentComponent,
      expirationTime,
      callback,
  );
}

updateContainerAtExpirationTime方法创建了context相关的对象,然后直接执行scheduleRootUpdate

scheduleRootUpdate

scheduleRootUpdate方法从RootFiber开始进行调度,主要做了3件事

  • 创建update, 当前update要更新的其实是ReactDOM.render的第一个参数,正常情况下是我们的 组件
  • 将update添加到当前Fiber(RootFiber)的updateQueue上面
  • 执行scheduleWork方法
typescript
function scheduleRootUpdate(
  current: Fiber,
  element: ReactNodeList,
  expirationTime: ExpirationTime,
  callback: ?Function,
) {
  const update = createUpdate(expirationTime);
  update.payload = {element};
  // 在一开始render的时候
  // 将当前组件的Element放在Fiber的updateQueue上
  enqueueUpdate(current, update);
  scheduleWork(current, expirationTime);
  return expirationTime;
}

scheduleWork的执行过程

createUpdate

react产生的更新,都是调用此方法创建的

typescript
export function createUpdate(expirationTime: ExpirationTime): Update<*> {
  return {
    expirationTime: expirationTime,

    tag: UpdateState,
    payload: null,
    callback: null,

    next: null,
    nextEffect: null,
  };
}

enqueueUpdate

enqueueUpdate是将当前update添加到队列里,此队列是一个单向链表, 具体的代码实现如下, 具体做了两件事:

  • 确保updateQueue被创建
  • 将update插入的链表尾部
typescript
export function enqueueUpdate<State>(fiber: Fiber, update: Update<State>) {
  // alternate 是更新中的那个fiber对象,更新完会跟Fiber交换位置
  // 也是Fiber架构双缓冲技术实现的关键
  const alternate = fiber.alternate;
  let queue1;
  let queue2;
  if (alternate === null) {
    // 如果alternate为空,说明是第一次渲染
    queue1 = fiber.updateQueue;
    queue2 = null;
    if (queue1 === null) {
      // 如果queue1是null, 则首先创建queue1
      queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState);
    }
  } else {
    // 说明不是第一次渲染,alternate在上一次渲染的时候已经创建了
    queue1 = fiber.updateQueue;
    queue2 = alternate.updateQueue;
    if (queue1 === null) {
      if (queue2 === null) {
        // 说明当前fiber还没有过更新,则创建queue1和queue2
        queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState);
        queue2 = alternate.updateQueue = createUpdateQueue(
            alternate.memoizedState,
        );
      } else {
        // 如果queue1不存在,但是queue2存在,那就把queue复制一份
        // 这种情况的出现可能是第第二次渲染后,产生了多个更新的情况
        // 第一次渲染没产生更新,但是第二次产生了多个更新
        queue1 = fiber.updateQueue = cloneUpdateQueue(queue2);
      }
    } else {
      if (queue2 === null) {
        // 如果queue1存在,但是queue2不存在,那就复制一份
        queue2 = alternate.updateQueue = cloneUpdateQueue(queue1);
      } else {
        // Both owners have an update queue.
      }
    }
  }
  // 上面的代码其实就是初始化queue1和queue2
  // 下面的才是真正的update加入的updateQueue
  if (queue2 === null || queue1 === queue2) {
    // 如果queue2不存在 或者两者相等,直接将update添加到队列中
    appendUpdateToQueue(queue1, update);
  } else {
    if (queue1.lastUpdate === null || queue2.lastUpdate === null) {
      // 其中一个队列是空的 ,都需要添加
      appendUpdateToQueue(queue1, update);
      appendUpdateToQueue(queue2, update);
    } else {
      //两个队列都不是空的。上一次更新在两个列表中都是相同的,
      //因为结构共享。所以,只需附加到其中一个列表。
      appendUpdateToQueue(queue1, update);
      // 更新一下queue2的指针
      queue2.lastUpdate = update;
    }
  }
}

注意

alternate是react Fiber架构下的缓存技术,在更新完后,会将alternate对应的Fiber和当前老的 Fiber交换位置, 具体的说明带扩展 TODO

备案号: 浙ICP备2023000081号