React16源码: React中的completeWork中对不同类型节点处理的源码实现

十一、深入理解 react中completeWork的工作流程 我们知道,当整个 Reconciler 完成工作后,会得到一颗完整的 wipFiberTree,这颗wipFiberTree是由 一颗一颗 FiberNode 中有一些标记了 flags,有一些没有标记,那么我们怎么能高效找到散落在这颗 树中有 flag标记的 ,那么此时就可以 通过 flags 冒泡。上面的代码,在FiberNode节点中,Hello 和 world 是同一级的,但是在实际dom元素里面,span 和 world 是同一级的。并且当前的FiberNode会标记 Update。 阅读详情

completeWork


1 )概述

  • 在 completeUnitOfWork 当中,在节点是正常渲染没有任何出错的情况下
  • 会去调用 completework,对这个节点进行一个完成工作的一系列操作
  • 在update各种component的时候,执行了各种获取context相关的内容
  • 对于 completeWork,我们会把它对应的这些节点获取的context再pop出来
  • 相当于 beginWork是一个正向的流程, 而completeWork 是一个反向的流程
  • 正向的流程获取的内容,反向的流程给它依次pop出来
  • 最终能够达到一个再被清空的一个流程
  • 对于 HostComponent 会执行一个节点的初始化以及更新的一个操作
  • 然后会初始化监听事件

2 )源码

定位到 packages/react-reconciler/src/ReactFiberCompleteWork.js#L540

进入 completeWork

function completeWork(
  current: Fiber | null,
  workInProgress: Fiber,
  renderExpirationTime: ExpirationTime,
): Fiber | null {
  // 获取当前 props
  const newProps = workInProgress.pendingProps;

  // 这里和 beginWork 里面的代码很像
  // 在这里面,很多的组件是没有任何的一个工作要做的
  // 相对于 class component,它也只需要去pop之前可能push进去过的一些内容
  switch (workInProgress.tag) {
    case IndeterminateComponent:
      break;
    case LazyComponent:
      break;
    case SimpleMemoComponent:
    case FunctionComponent:
      break;
    case ClassComponent: {
      const Component = workInProgress.type;
      if (isLegacyContextProvider(Component)) {
        popLegacyContext(workInProgress);
      }
      break;
    }
    // 对于 HostRoot,它也是各种 pop,因为 HostRoot 它会获取很多的一些内容
    case HostRoot: {
      popHostContainer(workInProgress);
      popTopLevelLegacyContextObject(workInProgress);
      const fiberRoot = (workInProgress.stateNode: FiberRoot);
      if (fiberRoot.pendingContext) {
        fiberRoot.context = fiberRoot.pendingContext;
        fiberRoot.pendingContext = null;
      }
      if (current === null || current.child === null) {
        // If we hydrated, pop so that we can delete any remaining children
        // that weren't hydrated.
        popHydrationState(workInProgress);
        // This resets the hacky state to fix isMounted before committing.
        // TODO: Delete this when we delete isMounted and findDOMNode.
        workInProgress.effectTag &= ~Placement;
      }
      // 最终它这边执行了一个叫做 updateHostContainer 这个方法
      // 那么这个方法在 react-dom 的环境下面是一个空的方法
      updateHostContainer(workInProgress);
      break;
    }
    // 最复杂的是 HostComponent 处理
    case HostComponent: {
      popHostContext(workInProgress);
      const rootContainerInstance = getRootHostContainer();
      const type = workInProgress.type;
      if (current !== null && workInProgress.stateNode != null) {
        updateHostComponent(
          current,
          workInProgress,
          type,
          newProps,
          rootContainerInstance,
        );

        if (current.ref !== workInProgress.ref) {
          markRef(workInProgress);
        }
      } else {
        if (!newProps) {
          invariant(
            workInProgress.stateNode !== null,
            'We must have new props for new mounts. This error is likely ' +
              'caused by a bug in React. Please file an issue.',
          );
          // This can happen when we abort work.
          break;
        }

        const currentHostContext = getHostContext();
        // TODO: Move createInstance to beginWork and keep it on a context
        // "stack" as the parent. Then append children as we go in beginWork
        // or completeWork depending on we want to add then top->down or
        // bottom->up. Top->down is faster in IE11.
        let wasHydrated = popHydrationState(workInProgress);
        if (wasHydrated) {
          // TODO: Move this and createInstance step into the beginPhase
          // to consolidate.
          if (
            prepareToHydrateHostInstance(
              workInProgress,
              rootContainerInstance,
              currentHostContext,
            )
          ) {
            // If changes to the hydrated node needs to be applied at the
            // commit-phase we mark this as such.
            markUpdate(workInProgress);
          }
        } else {
          let instance = createInstance(
            type,
            newProps,
            rootContainerInstance,
            currentHostContext,
            workInProgress,
          );

          appendAllChildren(instance, workInProgress, false, false);

          // Certain renderers require commit-time effects for initial mount.
          // (eg DOM renderer supports auto-focus for certain elements).
          // Make sure such renderers get scheduled for later work.
          if (
            finalizeInitialChildren(
              instance,
              type,
              newProps,
              rootContainerInstance,
              currentHostContext,
            )
          ) {
            markUpdate(workInProgress);
          }
          workInProgress.stateNode = instance;
        }

        if (workInProgress.ref !== null) {
          // If there is a ref on a host node we need to schedule a callback
          markRef(workInProgress);
        }
      }
      break;
    }
    // HostText 的处理
    case HostText: {
      let newText = newProps;
      if (current && workInProgress.stateNode != null) {
        const oldText = current.memoizedProps;
        // If we have an alternate, that means this is an update and we need
        // to schedule a side-effect to do the updates.
        updateHostText(current, workInProgress, oldText, newText);
      } else {
        if (typeof newText !== 'string') {
          invariant(
            workInProgress.stateNode !== null,
            'We must have new props for new mounts. This error is likely ' +
              'caused by a bug in React. Please file an issue.',
          );
          // This can happen when we abort work.
        }
        const rootContainerInstance = getRootHostContainer();
        const currentHostContext = getHostContext();
        let wasHydrated = popHydrationState(workInProgress);
        if (wasHydrated) {
          if (prepareToHydrateHostTextInstance(workInProgress)) {
            markUpdate(workInProgress);
          }
        } else {
          workInProgress.stateNode = createTextInstance(
            newText,
            rootContainerInstance,
            currentHostContext,
            workInProgress,
          );
        }
      }
      break;
    }
    case ForwardRef:
      break;
    // SuspenseComponent 的处理
    case SuspenseComponent: {
      const nextState = workInProgress.memoizedState;
      if ((workInProgress.effectTag & DidCapture) !== NoEffect) {
        // Something suspended. Re-render with the fallback children.
        workInProgress.expirationTime = renderExpirationTime;
        // Do not reset the effect list.
        return workInProgress;
      }

      const nextDidTimeout = nextState !== null;
      const prevDidTimeout = current !== null && current.memoizedState !== null;

      if (current !== null && !nextDidTimeout && prevDidTimeout) {
        // We just switched from the fallback to the normal children. Delete
        // the fallback.
        // TODO: Would it be better to store the fallback fragment on
        // the stateNode during the begin phase?
        const currentFallbackChild: Fiber | null = (current.child: any).sibling;
        if (currentFallbackChild !== null) {
          // Deletions go at the beginning of the return fiber's effect list
          const first = workInProgress.firstEffect;
          if (first !== null) {
            workInProgress.firstEffect = currentFallbackChild;
            currentFallbackChild.nextEffect = first;
          } else {
            workInProgress.firstEffect = workInProgress.lastEffect = currentFallbackChild;
            currentFallbackChild.nextEffect = null;
          }
          currentFallbackChild.effectTag = Deletion;
        }
      }

      // The children either timed out after previously being visible, or
      // were restored after previously being hidden. Schedule an effect
      // to update their visiblity.
      if (
        //
        nextDidTimeout !== prevDidTimeout ||
        // Outside concurrent mode, the primary children commit in an
        // inconsistent state, even if they are hidden. So if they are hidden,
        // we need to schedule an effect to re-hide them, just in case.
        ((workInProgress.effectTag & ConcurrentMode) === NoContext &&
          nextDidTimeout)
      ) {
        workInProgress.effectTag |= Update;
      }
      break;
    }
    case Fragment:
      break;
    case Mode:
      break;
    case Profiler:
      break;
    // 后续可以看到每一个基本上都是pop出来一些container,还有context相关的东西
    case HostPortal:
      popHostContainer(workInProgress);
      updateHostContainer(workInProgress);
      break;
    case ContextProvider:
      // Pop provider fiber
      popProvider(workInProgress);
      break;
    case ContextConsumer:
      break;
    case MemoComponent:
      break;
    case IncompleteClassComponent: {
      // Same as class component case. I put it down here so that the tags are
      // sequential to ensure this switch is compiled to a jump table.
      const Component = workInProgress.type;
      if (isLegacyContextProvider(Component)) {
        popLegacyContext(workInProgress);
      }
      break;
    }
    default:
      invariant(
        false,
        'Unknown unit of work tag. This error is likely caused by a bug in ' +
          'React. Please file an issue.',
      );
  }

  return null;
}
  • 关于 updateHostContainer, 不仅是这个方法,下面的方法
    • appendAllChildren
    • updateHostComponent
    • updateHostText
  • 以上4个,会根据环境的不同来执行不同的操作
  • 在 ReactDOMHostConfig.js 中 supportsMutation 为true
    • 这时候 updateHostContainer 就是一个空的方法
  • 这里主要关注,HostComponent 以及 HostText,在 completeWork 中的操作
  • 在这里,目前只看大致的流程,后续会对细节做具体的分析
react源码解析8.render阶段 react源码解析8.render阶段 视频讲解(高效学习):进入学习 往期文章: 1.开篇介绍和面试题 2.react的设计理念 3.react源码架构 4.源码目录结构和调试 5.jsx&核心api 6.legacy和concurrent模式入口函数 7.Fiber架构 8.render阶段 9.diff算法 10.commit阶段 11.生命周期 12.状态更新流程 13.hooks源码 14.手写hooks 15.scheduler&Lane 16.concurrent模式 17.c 阅读详情

相关推荐

【React源码 - Fiber架构之Reconciler】

React源码-Fiber架构之Reconciler

weixin_44273311的博客 2124

react源码分析(7)-completeWork介绍

目录 2021SC@SDUSC completeWork在源码中的大致位置 从beginWork到completeWork CompleteWork的工作流程 谈谈HostText 总结 2021SC@SDUSC completeWork在源码中的大致位置 在这里谈一下completeWork,首先我想明确一下位置,也就是大部分更新的执行流程,如图所示: 其中的performConcurrentWorkOnRoot正是react要求scheduler调度的fibe..

weixin_45668912的博客 502

12V转5V稳压电路详细分析(7805三端稳压,LM2596稳压)

7805线性三端稳压 DCDC的意思是直流变到直流(不同直流电源值的转换),只要符合这个定义都可以叫DCDC转换器,或称之为开关电源或开关调整器。 7805属于常用的线性三端稳压器,输入电压范围不大于35V,输入输出压差2V,最大输出电流1.5A,下图为原理图,其原理简单,使 用方便,深受很多用户的喜爱。但是其不足之处就是效率低,特别是压差越大时其效率越低。比如这里12V转5V的效率为 5V/12V≈41.7%。 如上电路是最经典的7805稳压5V电路,电路中有两个电容,电容的作用如下: ...

a2001444的博客 9万+

React16源码: React中的completeWork对HostComponent处理的源码实现

在 `completeWork` 当中,我们需要对 `HostComponent` 的一些操作有哪些? 首先在一次更新而不是初次渲染的情况下,需要去 `diffProperties` 来计算,需要更新的内容,也就是在 vdom 中去进行一个对比来判断这一个节点是否需要真的去更新它,以此来最低程度的去更新整个 dom 的一个过程,对于不同 dom property,它有一些不同的处理方式

Wang的专栏 1304

【Unity Shader】2D模型 3D模型混用的穿模问题(Spine在3D场景中出现前后穿模问题的解决办法)

问题描述: 在3D场景中使用Spine模型(2D), 因为Spine需要像Billboard类似的处理,永远是垂直与相机的, 所以一般情况下2D模型能正常显示且前后的阻挡关系也是没有问题的,如下图所示,一切都很美好.(这里用一个四边形,图中的福字表示2D模型) 可是如果后面蓝色的格子比较高,或者2D角色本身也比较高,那么就会出现模型穿插的问题,如下图所示: 如果吧2D模型竖立起来,前后关系肯定是没有问题的,所以也能避免模型穿插的问题,可是就没有Billboard效果,圆形的福字已经被压扁了,如下图:

Vitens的专栏 4594

Ubuntu桌面消失?可能是lightdm配置在捣鬼:详细解析/etc/lightdm.conf的优先级机制与实战修复

本文详细解析了Ubuntu系统因lightdm显示管理器配置错误导致桌面消失的问题。通过分析/etc/lightdm.conf的优先级加载机制,提供了从systemctl诊断、调试模式运行到实战修复配置语法错误(如缺失[Seat:*]组)的完整方案。文章还探讨了在系统无法启动时使用chroot或恢复模式进行高级救援,并对比了lightdm与gdm3在NVIDIA驱动环境下的不同表现,帮助用户高效恢复图形界面。

weixin_29313547的博客 420

React16源码: React中的completeWork对HostText处理含更新的源码实现

HostText 相比于 HostComponents 来说,它没有多种选择。没有各种各样的属性,整体来说非常的简单。一些特别说明的,写在了上述代码注释中。

Wang的专栏 1242

SAP ABAP开发避坑:BAPI_MATVAL_PRICE_CHANGE调用报‘估价未维护’的完整解决流程

本文深入解析SAP ABAP开发中调用BAPI_MATVAL_PRICE_CHANGE函数时遇到的'估价未维护'错误,提供从基础配置检查到CKML_PRICE_SEND表维护的完整解决方案。通过实战案例和代码示例,帮助开发者快速定位问题并实现批量价格更新的自动化处理,提升开发效率。

weixin_28705087的博客 428

【React源码09】深入学习React 源码实现——Fiber架构副作用收集Effect List

React Fiber架构通过副作用收集机制实现了高效更新。在协调阶段(render phase),React遍历Fiber树并标记需要执行的DOM操作(如插入、更新、删除),将这些副作用收集到effectList中。在提交阶段(commit phase),React批量执行这些副作用到真实DOM。这种机制使React能够灵活调度任务,支持并发特性,同时保持高效的更新性能。

silverclayz的技术分享 1304

告别Sourceforge安装器!手把手教你下载MinGW-w64离线包并配置环境变量(Windows 10/11)

本文详细介绍了如何在Windows 10/11系统上通过下载MinGW-w64离线包并配置环境变量,完全绕过Sourceforge安装器的问题。从选择正确的版本、解压到本地目录,到设置系统环境变量和验证编译环境,手把手指导开发者快速搭建稳定的GCC编译环境,解决常见的安装困扰。

weixin_30896825的博客 338

机器学习---xgboost算法

问题上表现的十分顶尖,本节将较详细的介绍XGBoost的算法原理。成和剪枝分别对应了经验风险最小化和结构风险最小化, XGBoost的决策树生成是结构风险最小。式(1.1)称为经验风险最小化,训练得到的模型复杂度较高。出结果, 是模型的输出结果;等式右边第⼀部分是模型的训练误差,第⼆部分是正则化项,这里。其中,F是假设空间,假设空间是在已知属性和属性可能取值的情况下,对所有可能满足目标的情。最小化,结构风险最小化的模型往往对训练数据以及未知的测试数据都有较好的预测。的正则化项是K棵树的正则化项相加而来的。

weixin_43961909的博客 1万+

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

在 `completeWork` 阶段的 `HostComponent` 处理,继续前文所述, 在更新的逻辑里面,调用了 `updateHostComponent` , 进行前后props对应的dom的attributes变化的对比情况,这个方法也是根据不同环境来定义的,我们这里只专注于 react-dom 环境

Wang的专栏 1278

[uboot] (第四章)uboot流程——uboot编译流程

uboot编译流程简单介绍

ooonebook的博客 1万+

react源码debugger-各种fiber的completeWork阶段

原生div p标签等的bieginWork class DD extends Component { render() { return <div>123</div>; } } 上面调式了DD类组件的fiber,接着看类组件返回的子fiber,div标签的fiber是怎样的。 对于原生html的fiber,fiber.tag是5 export const HostComponent = 5; //原生标签 hostComponent的fiber { altern

lin_fightin的博客 415

保姆级教程:用DaVinci Configurator & Developer从零搭建AUTOSAR OS(TC2xx三核实战)

本文提供了一份详细的AUTOSAR OS配置指南,使用DaVinci Configurator和Developer工具从零开始搭建Infineon TC2xx三核系统。涵盖多核配置协同逻辑、版本兼容性陷阱及验证错误的解决方案,帮助开发者在3小时内构建可运行的多核OS框架。

weixin_33940469的博客 317

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

【React源码08】深入学习React 源码实现——Fiber架构双缓冲(current 与 workInProgress)机制

React的双缓冲机制(current与workInProgress)是Fiber架构的核心特性,通过两棵Fiber树的交替使用实现高效的UI更新。在更新过程中,React基于current树创建workInProgress树,所有更新操作在workInProgress树上进行,完成后通过commitRoot提交并切换指针。这种机制允许React保留当前状态,并支持中断/恢复渲染。源码中createWorkInProgress函数负责节点的创建/复用,通过alternate指针实现双树快速切换。

silverclayz的技术分享 944

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

React源码解析————Render阶段(一)

React源码解析————ReactHooks(四)2021SC@SDUSC前言 2021SC@SDUSC 2021SC@SDUSC 前言 为了巩固我们对react hooks的理解,我们尝试去构建一个简单useState

m0_51744158的博客 874

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

react源码解析8.render阶段(看我会对比Fiber哦)

react源码解析8.render阶段 视频讲解(高效学习):进入学习 往期文章: 1.开篇介绍和面试题 2.react的设计理念 3.react源码架构 4.源码目录结构和调试 5.jsx&核心api 6.legacy和concurrent模式入口函数 7.Fiber架构 8.render阶段 9.diff算法 10.commit阶段 11.生命周期 12.状态更新流程 13.hooks源码 14.手写hooks 15.scheduler&Lane 16.concurrent模式 17.c

zz2000aa的博客 260

React 源码 - Render Phase 的工作细节

在 Render 阶段对单个 Fiber 做好“更新准备”,并把它的“副作用”记下来:在这之上实现「深度优先后序遍历」(先子节点、再兄弟、再父节点),确保整棵 Fiber 树的每个节点都被处理到先“向下”调和,再“向上”归并,不碰 DOM,只收集副作用。

2401_85392853的博客 1218

react16 Fiber架构的实现

Fiber概念和背景 为什么叫fiber 对于进程(Process)和线程(Thread)的概念,我们应该比较了解,在计算机科学中还有一个概念叫做Fiber,英文含义就是“纤维”,意指比Thread更细的线,也就是比线程(Thread)控制得更精密的并发处理机制。react把最新的调度架构取名为fiber,也意为实现更精密的任务控制。但是react fiber和这个fiber是不同的两个概念。...

前端361 831

react源码 递阶段mount时阶段

react源码 递阶段mount时阶段

qq_56303170的博客 611

第 3 周:Fiber 架构原理(调和流程)

从 React 元素(JSX)转成 Fiber 节点通过 beginWork 构建子 Fiber(递)通过 completeWork 完成当前 Fiber(归)收集 effect 到 EffectListcommitWork 真正执行 DOM 操作。

1295

浅谈react——状态更新之后发生了什么

学习react底层的过程,和学习其他原理一样,抓住一些关健的点,也就是关键的函数(往往代表了一些阶段),可以对源码的把握以及 图像化的流程更加清晰和易懂。 我们知道facebook团队在react16之后就对react底层有一些重大的重构,一句大白话来解释就是,让react可以实现异步可中断的更新。 至于怎么实现的,是react引入了Scheduler调度器,会分配给js线程一个初始的执行时间,源码里面yieldInterval=5ms,如果预留的时间不够浏览器渲染的话,那么react就会将控制权.

m0_60360320的博客 663
上一篇: React16源码: React中的resetChildExpirationTime的源码实现
下一篇: React16源码: React中的completeWork对HostComponent处理的源码实现
Wang's Blog
博客等级 码龄12年 7438粉丝 2421原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值