React源码学习笔记---render流程(2)

189 阅读2分钟

ReactRoot.prototype.render

上文是创建了root节点,这一篇是创建之后发生的事情

    // batchedUpdate 是 React 中很重要的一步,也就是批量更新
    // this.setState({ age: 1 })
    // this.setState({ age: 2 })
    // this.setState({ age: 3 })
    // 以上三次 setState 会被优化成一次更新,减少了渲染次数
    // 但是对于 Root 来说没必要批量更新,直接调用回调函数
    unbatchedUpdates(() => {
      // 上文中传入的parentComponent为null,所以直接进入render
      // 其实也不是没可能存在 parentComponent,如果在 root 上使用 context 就可以了
      if (parentComponent != null) {
        root.legacy_renderSubtreeIntoContainer(
          parentComponent,
          children,
          callback,
        );
      } else {
        // 调用的是 ReactRoot.prototype.render
        root.render(children, callback);
      }
    });
ReactRoot.prototype.render = function(
  children: ReactNodeList,
  callback: ?() => mixed,
): Work {
  // 这里指 FiberRoot
  const root = this._internalRoot;
  // ReactWork 的功能就是为了在组件渲染或更新后把所有传入
  // ReactDom.render 中的回调函数全部执行一遍
  const work = new ReactWork();
  callback = callback === undefined ? null : callback;
  // 如果有 callback,就 push 进 work 中的数组
  if (callback !== null) {
    work.then(callback);
  }
  // work._onCommit 就是用于执行所有回调函数的
  updateContainer(children, root, null, work._onCommit);
  return work;
};

updateContainer

我们先从 FiberRoot 的 current 属性中取出它的 fiber 对象,然后计算了两个时间。这两个时间在 React 中相当重要。 只需要记住任务的过期时间是通过当前时间加上一个常量(任务优先级不同常量不同)计算出来的

function updateContainer(
  element: ReactNodeList,
  container: OpaqueRoot,
  parentComponent: ?React$Component<any, any>,
  callback: ?Function,
): ExpirationTime {
  // 取出容器的 fiber 对象,也就是 fiber root
  const current = container.current;
  // 计算时间
  const currentTime = requestCurrentTime();
  // expirationTime 代表优先级,数字越大优先级越高
  // sync 的数字是最大的,所以优先级也是最高的
  const expirationTime = computeExpirationForFiber(currentTime, current);
  
  // updateContainerAtExpirationTime这个函数直接返回scheduleRootUpdate,所以直接看它
  return updateContainerAtExpirationTime(
    element,
    container,
    parentComponent,
    expirationTime,
    callback,
  );
}

scheduleRootUpdate

function scheduleRootUpdate(
  current: Fiber,
  element: ReactNodeList,
  expirationTime: ExpirationTime,
  callback: ?Function,
) {
  // 创建一个 update,就是内部有几个属性的对象
  const update = createUpdate(expirationTime);
  // 第一次render直接将element当做payload    
  // being called "element".
  update.payload = {element};

  callback = callback === undefined ? null : callback;
  if (callback !== null) {
    update.callback = callback;
  }

  // 把 update 入队,内部就是一些创建或者获取 queue(链表结构),然后给链表添加一个节点的操作
  enqueueUpdate(current, update);
  // 调度相关
  scheduleWork(current, expirationTime);

  return expirationTime;
}

createUpdate

这个方法返回的对象和setState有关

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

    tag: UpdateState,
    // setState 的第一二个参数
    payload: null,
    callback: null,
    // 用于在队列中找到下一个节点
    next: null,
    nextEffect: null,
  };
}

render的整体流程