React16源码: React中的updateHostRoot的源码实现

HostRoot 的更新

1 )概述

  • HostRoot 是一个比较特殊的节点, 因为在一个react应用当中
  • 它只会有一个 HostRoot, 它对应的 Fiber 对象是我们的 RootFiber 对象
  • 重点在于它的更新过程

2 )源码

定位到 packages/react-reconciler/src/ReactFiberBeginWork.js#L612

js 复制代码
// 这个函数的重点在: update 来自哪里, 里面是什么内容
// 最终通过 processUpdateQueue 得到了 element 里面的内容,之后以此作为children来调和
function updateHostRoot(current, workInProgress, renderExpirationTime) {
  // 跳过 context 相关
  pushHostRootContext(workInProgress);
  const updateQueue = workInProgress.updateQueue;
  invariant(
    updateQueue !== null,
    'If the root does not have an updateQueue, we should have already ' +
      'bailed out. This error is likely caused by a bug in React. Please ' +
      'file an issue.',
  );
  // 获取一系列数据
  const nextProps = workInProgress.pendingProps;
  const prevState = workInProgress.memoizedState;
  // 对于 HostRoot 一开始是没有 state,也就是 `prevState.element`, 在第一次渲染的时候,prevState 是 null,在ReactDOM.render中创建了一个update
  // 经过 processUpdateQueue 这次更新后,它会拿到一个 {element} 对象作为 state
  const prevChildren = prevState !== null ? prevState.element : null;
  // 得到创建的update传递的element
  processUpdateQueue(
    workInProgress,
    updateQueue,
    nextProps,
    null,
    renderExpirationTime,
  );
  const nextState = workInProgress.memoizedState;
  // Caution: React DevTools currently depends on this property
  // being called "element".
  const nextChildren = nextState.element;
  if (nextChildren === prevChildren) {
    // If the state is the same as before, that's a bailout because we had
    // no work that expires at this time.
    resetHydrationState(); // 服务端渲染,复用dom节点相关内容
    // 跳出更新过程,不需要更新
    // 对 RootFiber来说,大部分情况下,只在 ReactDOM.render 的时候有更新,其他时候都不需要更新
    // 一般都是在App内更新,不会在RootFiber节点创建更新
    return bailoutOnAlreadyFinishedWork(
      current,
      workInProgress,
      renderExpirationTime,
    );
  }
  const root: FiberRoot = workInProgress.stateNode;
  // 跳过 hydrate 相关
  if (
    (current === null || current.child === null) &&
    root.hydrate &&
    enterHydrationState(workInProgress)
  ) {
    // If we don't have any current children this might be the first pass.
    // We always try to hydrate. If this isn't a hydration pass there won't
    // be any children to hydrate which is effectively the same thing as
    // not hydrating.

    // This is a bit of a hack. We track the host root as a placement to
    // know that we're currently in a mounting state. That way isMounted
    // works as expected. We must reset this before committing.
    // TODO: Delete this when we delete isMounted and findDOMNode.
    workInProgress.effectTag |= Placement;

    // Ensure that children mount into this root without tracking
    // side-effects. This ensures that we don't store Placement effects on
    // nodes that will be hydrated.
    // 在 current === null || current.child === null 这种情况下,都是第一次渲染
    workInProgress.child = mountChildFibers(
      workInProgress,
      null,
      nextChildren,
      renderExpirationTime,
    );
  } else {
    // Otherwise reset hydration state in case we aborted and resumed another
    // root.
    // 不是第一次渲染
    reconcileChildren(
      current,
      workInProgress,
      nextChildren,
      renderExpirationTime,
    );
    resetHydrationState();
  }
  return workInProgress.child;
}
  • HostRoot 创建更新的过程就是在 ReactFiberReconciler.js 中的调用 ReactDOM.render 的过程

  • 定位到 scheduleRootUpdate 位置在 packages/react-reconciler/src/ReactFiberReconciler.js#L110

    js 复制代码
    function scheduleRootUpdate(
      current: Fiber,
      element: ReactNodeList,
      expirationTime: ExpirationTime,
      callback: ?Function,
    ) {
      // ... 省略
      const update = createUpdate(expirationTime);
      update.payload = {element};
      // ... 省略
      return expirationTime;
    }
    • 它这里创建一个 update, 并挂在 update.payload 是 {element}
    • 这个 element 就是传给 ReactDOM.render 的第一个参数
    • 这个 update 对象没有后续指定类型
    • 这和调用 setState 在组件内创建更新效果是类似的
    • 所以,update.payload 就相当于 state
    • 对于 HostRoot 来说, 它的state只有一个属性,就是element
    • 就是 ReactDOM.render 的第一个参数
相关推荐
崔庆才丨静觅2 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60613 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了3 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅3 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅3 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅4 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment4 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅4 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊4 小时前
jwt介绍
前端
爱敲代码的小鱼4 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax