当前位置: 首页 > news >正文

React16源码: React中commit阶段的commitBeforeMutationLifecycles的源码实现

commitBeforeMutationLifecycles


1 )概述

  • 在 react commit 阶段的 commitRoot 第一个while循环中
  • 调用了 commitBeforeMutationLifeCycles
  • 现在来看下,里面发生了什么

2 )源码

回到 commit 阶段的第一个循环中,在 commitRoot 函数里
定位到 packages/react-reconciler/src/ReactFiberScheduler.js#L647

看这里

// Invoke instances of getSnapshotBeforeUpdate before mutation.
nextEffect = firstEffect;
startCommitSnapshotEffectsTimer();// 接下去就进入了三个循环:
// 第一个循环主要是 commitBeforeMutationLifecycles,这个方法它其实很简单,它是这三个循环当中最简单的一个方法
// 它唯一的作用就是调用 ClassComponent 上面可能会存在的 getSnapshotBeforeUpdate 这么一个生命周期方法
while (nextEffect !== null) {let didError = false;let error;if (__DEV__) {invokeGuardedCallback(null, commitBeforeMutationLifecycles, null);if (hasCaughtError()) {didError = true;error = clearCaughtError();}} else {try {commitBeforeMutationLifecycles();} catch (e) {didError = true;error = e;}}if (didError) {invariant(nextEffect !== null,'Should have next effect. This error is likely caused by a bug ' +'in React. Please file an issue.',);captureCommitPhaseError(nextEffect, error);// Clean-upif (nextEffect !== null) {nextEffect = nextEffect.nextEffect;}}
}
  • 在开始循环之前都会用到一个全局变量叫做 nextEffect,当然它一开始是 firstEffect
    • 是在 RootFiber 上面,它的 firstEffect 到 lastEffect 这个链表上面的第一个effect
    • 也就是第一个需要我们commit的fiber对象
  • 需要注意一点,这边有一个很奇怪的代码,就是我们这个 commitBeforeMutationLifecycles 方法
    • 可以看到 import { commitBeforeMutationLifeCycles } from './ReactFiberCommitWork'
    • 但是又在本文件中,定义了一个同名的方法
      // 这个是核心
      function commitBeforeMutationLifecycles() {while (nextEffect !== null) {if (__DEV__) {ReactCurrentFiber.setCurrentFiber(nextEffect);}const effectTag = nextEffect.effectTag;if (effectTag & Snapshot) {recordEffect();const current = nextEffect.alternate;commitBeforeMutationLifeCycles(current, nextEffect); // 这个函数,不是上层的自己,而是 import 进来的}nextEffect = nextEffect.nextEffect;}if (__DEV__) {ReactCurrentFiber.resetCurrentFiber();}
      }
      
  • 这个操作会有点奇怪,因为正常来讲,import 进来的内容,它是一个常量,它不应该是能够直接被修改
  • 注意,在 commitRoot 里调用的 commitBeforeMutationLifeCycles 是文件内的这个方法
  • 而文件内的这个方法,调用的 commitBeforeMutationLifeCycles 是 import 进来的
    • 它来自于 packages/react-reconciler/src/ReactFiberCommitWork.js#L215
  • 它通过一个while循环,循环的是我们的 effect链
    • 在这个循环的后面,可以看到 nextEffect = nextEffect.nextEffect;
  • 这就是说一个一个往下这么去循环,对 有 Snapshot 这个 SideEffect 的节点执行了下面的方法

再次定位到 packages/react-reconciler/src/ReactFiberCommitWork.js#L215

进入 commitBeforeMutationLifeCycles 这个就是上面定义的同名函数里面调用的方法

function commitBeforeMutationLifeCycles(current: Fiber | null,finishedWork: Fiber,
): void {switch (finishedWork.tag) {case FunctionComponent:case ForwardRef:case SimpleMemoComponent: {commitHookEffectList(UnmountSnapshot, NoHookEffect, finishedWork);return;}case ClassComponent: {if (finishedWork.effectTag & Snapshot) {if (current !== null) {const prevProps = current.memoizedProps;const prevState = current.memoizedState;startPhaseTimer(finishedWork, 'getSnapshotBeforeUpdate');const instance = finishedWork.stateNode;// We could update instance props and state here,// but instead we rely on them being set during last render.// TODO: revisit this when we implement resuming.if (__DEV__) {if (finishedWork.type === finishedWork.elementType) {warning(instance.props === finishedWork.memoizedProps,'Expected instance props to match memoized props before ' +'getSnapshotBeforeUpdate. This is likely due to a bug in React. ' +'Please file an issue.',);warning(instance.state === finishedWork.memoizedState,'Expected instance state to match memoized state before ' +'getSnapshotBeforeUpdate. This is likely due to a bug in React. ' +'Please file an issue.',);}}const snapshot = instance.getSnapshotBeforeUpdate(finishedWork.elementType === finishedWork.type? prevProps: resolveDefaultProps(finishedWork.type, prevProps),prevState,);if (__DEV__) {const didWarnSet = ((didWarnAboutUndefinedSnapshotBeforeUpdate: any): Set<mixed,>);if (snapshot === undefined && !didWarnSet.has(finishedWork.type)) {didWarnSet.add(finishedWork.type);warningWithoutStack(false,'%s.getSnapshotBeforeUpdate(): A snapshot value (or null) ' +'must be returned. You have returned undefined.',getComponentName(finishedWork.type),);}}instance.__reactInternalSnapshotBeforeUpdate = snapshot;stopPhaseTimer();}}return;}case HostRoot:case HostComponent:case HostText:case HostPortal:case IncompleteClassComponent:// Nothing to do for these component typesreturn;default: {invariant(false,'This unit of work tag should not have side-effects. This error is ' +'likely caused by a bug in React. Please file an issue.',);}}
}
  • 它传入的 current 是 workInProgress 对象,也就是fiber对象
  • 然后传入的 nextEfect 是 finishedWork 对象
  • 通过 instance.getSnapshotBeforeUpdate 传入两个 props 来获取 snapshot 快照对象
  • 之后将 snapshot 挂载到 instance.__reactInternalSnapshotBeforeUpdate
  • 对于其他类型的组件,它都没有任何的处理,只处理了 ClassComponent
  • 因为对这种情况来说,只有 ClassComponent 有这个 SideEffect
  • 并且会有 getSnapshotBeforeUpdate 这个生命周期方法的

相关文章:

React16源码: React中commit阶段的commitBeforeMutationLifecycles的源码实现

commitBeforeMutationLifecycles 1 &#xff09;概述 在 react commit 阶段的 commitRoot 第一个while循环中调用了 commitBeforeMutationLifeCycles现在来看下&#xff0c;里面发生了什么 2 &#xff09;源码 回到 commit 阶段的第一个循环中&#xff0c;在 commitRoot 函数…...

压制二元组的总价值

压制二元组的总价值 对于每一个 a i a_i ai​, 看它能压制它前面的多少个元素, 那么它对总价值的贡献就是: 在a数组中: a i a_i ai​压制了x个数, 贡献为: x ∗ i x*i x∗i被 a i a_i ai​所压制的所有数在 a a a中的下标和为 y y y, 贡献为 − y -y −y 树状数组来求: 为了…...

【习题】保存应用数据

判断题 1. 首选项是关系型数据库。 错误(False) 2. 应用中涉及到Student信息&#xff0c;如包含姓名&#xff0c;性别&#xff0c;年龄&#xff0c;身高等信息可以用首选项来存储。 错误(False) 3. 同一应用或进程中每个文件仅存在一个Preferences实例。 正确(True) 单选题 …...

Flask框架小程序后端分离开发学习笔记《5》简易服务器代码

Flask框架小程序后端分离开发学习笔记《5》 Flask是使用python的后端&#xff0c;由于小程序需要后端开发&#xff0c;遂学习一下后端开发。 简易服务器代码 接口解析那一块很关键&#xff0c;学后端服务器这一块&#xff0c;感觉主要就是学习相应地址的接口怎么处理。 然后…...

“计算机视觉处理设计开发工程师”专项培训(第二期)

“人工智能技术与咨询” 发布...

R语言学习case7:ggplot基础画图(核密度图)

step1: 导入ggplot2库文件 library(ggplot2)step2&#xff1a;带入自带的iris数据集 iris <- datasets::irisstep3&#xff1a;查看数据信息 dim(iris)维度为 [150,5] head(iris)查看数据前6行的信息 step4&#xff1a;画图展示 plot2 <- ggplot(iris,aes(Sepal.W…...

Ubuntu18配置Docker

1.基本过程 1.更新软件源列表 sudo apt update2.安装软件包依赖 sudo apt install apt-transport-https ca-certificates curl software-properties-common3.在系统中添加Docker的官方密钥 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - …...

Keil/MDK平台 - 结构体成员指针注意事项

文章目录 1 . 前言总结2 . 问题现象3 . 解决思路4 . 细节扩展5 . 总结 【极客技术传送门】 : https://blog.csdn.net/Engineer_LU/article/details/135149485 1 . 前言总结 有时候希望通过类定义的类型指向数据包来解析&#xff0c;恰好又想结构体内定义指针指向一段数据&…...

一款超级好用的远程控制APP,你值得拥有

在这个科技日新月异的时代&#xff0c;我们的生活被各种手机软件所包围。几乎每个人都有一个甚至多个手机&#xff0c;你是否也有遇到过需要远程操作自己某一台手机的场景呢&#xff1f;今天&#xff0c;我要向大家推荐一款神奇的手机远程操作神器&#xff0c;让你可以随时随地…...

NumPy必知必会50例 | 18. 使用 NumPy 解决线性方程组:数学问题的实用解决方案

继续我们的 NumPy 探索之旅吧&#xff0c;接下来我们将探讨使用 NumPy 解决线性方程组&#xff0c;一种实用的数学应用。 文章目录 18. 使用 NumPy 解决线性方程组&#xff1a;数学问题的实用解决方案线性方程组&#xff1a;数学世界的基石创建线性方程组 解决实际问题应用场景…...

C/C++编码问题研究

文章目录 一、Unicode字符集与U8/U16/U32编码二、编码1. 占字节数2. ASCII、GB2312、GBK、GB18030 以及 UTF8 的关系3. BOM4. UTF-8的存储实现 三、编译器字符集设置1. GCC语法Example 2. MSVC语法Example 三、wchar_t五、编码转换函数六、代码 & 实践1. UTF8与UTF16、UTF3…...

二刷代码随想录|Java版|回溯算法3|子集问题

习题 2.3 子集问题 就是组合过程收集path。就像是代码随想录里说得那样&#xff0c;组合和分割问题就是收集叶子结点&#xff0c;子集问题就是收集每一个节点。 有涉及到同层重复元素的问题。 先排序&#xff0c;后再for循环里处理相同数值跳过。 设置函数内的used。 还可以用…...

mongodb config

windows&#xff1a; 1.同级bin&#xff0c;data&#xff0c;log创建mongo.config文件 dbpathD:\Program\mongodb\data\db logpathD:\Program\mongodb\log\mongo.log logappendtrue #默认启用日志 journaltrue #过滤无用日志信息&#xff0c;调试设置为false quiettrue port2…...

pytorch 实现中文文本分类

&#x1f368; 本文为[&#x1f517;365天深度学习训练营学习记录博客&#x1f366; 参考文章&#xff1a;365天深度学习训练营&#x1f356; 原作者&#xff1a;[K同学啊 | 接辅导、项目定制]\n&#x1f680; 文章来源&#xff1a;[K同学的学习圈子](https://www.yuque.com/mi…...

【MySQL】聚合函数和内置函数

文章目录 1 :peach:聚合函数:peach:2 :peach:group by子句的使用:peach:3 :peach:内置函数:peach:3.1 :apple:日期函数:apple:3.2 :apple:字符串函数:apple:3.3 :apple:数学函数:apple: 4 :peach:其它函数:peach: 1 &#x1f351;聚合函数&#x1f351; 函数说明COUNT([DISTIN…...

python第五节:集合set(4)

集合其他方法&#xff1a; len(s) set 的长度 x in s x 是否是 s 的成员 x not in s x 是否不是 s 的成员 s.issubset(t) 是否 s 中的每一个元素都在 t 中 s.issuperset(t) 是否 t 中的每一个元素都在 s s.union(t) 返回一个新的 set 包含 s 和 t 中的每一个元素 …...

知识笔记(一百)———什么是okhttp?

OkHttp简介&#xff1a; OkHttp 是一个开源的、高效的 HTTP 客户端库&#xff0c;由 Square 公司开发和维护。它为 Android 和 Java 应用程序提供了简单、强大、灵活的 HTTP 请求和响应的处理方式。OkHttp 的设计目标是使网络请求变得更加简单、快速、高效&#xff0c;并且支持…...

Electron桌面应用实战:Element UI 导航栏橙色轮廓之谜与Bootstrap样式冲突解决方案

目录 引言 问题现象及排查过程 描述问题 深入探索 查明原因 解决方案与策略探讨 重写样式 禁用 Bootstrap 样式片段 深度定制 Element UI 组件 隔离样式作用域 结语 引言 在基于 Electron 开发桌面应用的过程中&#xff0c;我们可能时常遇到各种意想不到的问题…...

Nuget包缓存存放位置迁移

一、背景 默认情况下&#xff0c;NuGet会将项目中使用的包缓存到C盘&#xff0c;随着项目开发积累nuget包越来越多&#xff0c;这会逐渐挤占大量C盘空间&#xff0c;所以我们可以将nuget包缓存位置指定到其他盘中存放。 二、软件环境 win10、vs2022 三、查看当前缓存存放位…...

键盘上Ins键的作用

前几天编写文档时&#xff0c;发现一个问题&#xff1a;插入内容时&#xff0c;输入的字符将会覆盖光标位置后的字符。原来是按到了键盘上的 Ins键&#xff0c;解决方法是&#xff1a;再按一次 Ins键&#xff08;Ins键如果独立作为一键时&#xff0c;否则使用 “Fn Ins”组合键…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

3.3.1_1 检错编码(奇偶校验码)

从这节课开始&#xff0c;我们会探讨数据链路层的差错控制功能&#xff0c;差错控制功能的主要目标是要发现并且解决一个帧内部的位错误&#xff0c;我们需要使用特殊的编码技术去发现帧内部的位错误&#xff0c;当我们发现位错误之后&#xff0c;通常来说有两种解决方案。第一…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

【git】把本地更改提交远程新分支feature_g

创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...

【生成模型】视频生成论文调研

工作清单 上游应用方向&#xff1a;控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)

船舶制造装配管理现状&#xff1a;装配工作依赖人工经验&#xff0c;装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书&#xff0c;但在实际执行中&#xff0c;工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing

Muffin 论文 现有方法 CRADLE 和 LEMON&#xff0c;依赖模型推理阶段输出进行差分测试&#xff0c;但在训练阶段是不可行的&#xff0c;因为训练阶段直到最后才有固定输出&#xff0c;中间过程是不断变化的。API 库覆盖低&#xff0c;因为各个 API 都是在各种具体场景下使用。…...

LCTF液晶可调谐滤波器在多光谱相机捕捉无人机目标检测中的作用

中达瑞和自2005年成立以来&#xff0c;一直在光谱成像领域深度钻研和发展&#xff0c;始终致力于研发高性能、高可靠性的光谱成像相机&#xff0c;为科研院校提供更优的产品和服务。在《低空背景下无人机目标的光谱特征研究及目标检测应用》这篇论文中提到中达瑞和 LCTF 作为多…...