我的编程空间,编程开发者的网络收藏夹
学习永远不晚

简单分析React中的EffectList

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

简单分析React中的EffectList

React中,会遍历EffectList来执行节点操作、生命周期方法、Effect方法,可以把EffectList比作圣诞树上挂的彩灯,而这颗圣诞树就是Fiber树。

为什么会存在EffectList呢?打个比方来说,一颗Fiber树中有一些Fiber节点需要执行componentDidMount方法,如果在Fiber树构建完成后,再遍历一次Fiber树,找到需要执行componentDidMount方法的Fiber节点,这是非常低效的。

而EffectList就解决了这个问题,在Fiber树构建过程中,每当一个Fiber节点的flags字段不为NoFlags时(代表需要执行副作用),就把该Fiber节点添加到EffectList,在Fiber树构建完成后,由Fiber节点串成的彩灯也构建完成了,这样仅仅需要遍历彩灯就行了。

EffectList的收集

EffectList是一个单向链表,firstEffect代表链表中的第一个Fiber节点,lastEffect代表链表中的最后一个Fiber节点。

Fiber树的构建是深度优先的,也就是先向下构建子级Fiber节点,子级节点构建完成后,再向上构建父级Fiber节点,所以EffectList中总是子级Fiber节点在前面。

Fiber节点构建完成的操作执行在completeUnitOfWork方法,在这个方法里,不仅会对节点完成构建,也会将有flags的Fiber节点添加到EffectList。

简化代码如下。


function completeUnitOfWork(unitOfWork: Fiber): void {
 let completedWork = unitOfWork;
 do {
  const current = completedWork.alternate;
  const returnFiber = completedWork.return;
  
  let next= completeWork(current, completedWork, subtreeRenderLanes);

  // effect list构建
  if (
   returnFiber !== null &&
   (returnFiber.flags & Incomplete) === NoFlags
  ) {
   // 层层拷贝
   if (returnFiber.firstEffect === null) {
    returnFiber.firstEffect = completedWork.firstEffect;
   }
   if (completedWork.lastEffect !== null) {
    // 说明当前节点是兄弟节点,子节点有effect,已经给returnFiber.lastEffect赋值过了
    if (returnFiber.lastEffect !== null) {
     // 连接兄弟节点的effect
     returnFiber.lastEffect.nextEffect = completedWork.firstEffect;
    }
    returnFiber.lastEffect = completedWork.lastEffect;
   }
   
   const flags = completedWork.flags;
   
   // 该fiber节点有effect
   if (flags > PerformedWork) {
    // 当前节点有effect连接上effect list
    if (returnFiber.lastEffect !== null) {
     returnFiber.lastEffect.nextEffect = completedWork;
    } else {
     // returnFiber没有firstEffect的情况是第一次遇见有effect的节点
     returnFiber.firstEffect = completedWork;
    }
    returnFiber.lastEffect = completedWork;
   }
  }

  // 兄弟元素遍历再到返返回父级
  const siblingFiber = completedWork.sibling;
  if (siblingFiber !== null) {
   workInProgress = siblingFiber;
   return;
  }
  completedWork = returnFiber;
  workInProgress = completedWork;
 } while (completedWork !== null);
}

EffectList实际是像冒泡一样,一层一层不断向上层收集,从第一个有flags的节点开始记录,每层的新节点都会将上一个节点的firstEffectlastEffect拷贝到自身身上,再供上层节点再次拷贝。

如以下结构,假如每一个div都有flags


<div id="1">
 <div id="4"/>
 <div id="2">
  <div id="3"/>
 </div>
</div>

最终形成的EffectList为


firstEffect => div4
lastEffect => div1

因为Fiber树的构建深度优先,所有div4先完成completeWork,构建firstEffect

EffectList遍历是从firstEffect开始,通过每一个节点的nextEffect找到下一个节点。


firstEffect => div4
div4.nextEffect => div3
div3.nextEffect => div2
div2.nextEffect => div1

初次Render时的EffectList

在React中,会对初次Mount有一个性能优化,其中的Fiber节点的flags不会包含placement,对应的DOM节点不会遍历加入DOM树,而是在创建DOM节点时就已经加入DOM树了,只有rootFiber节点FiberRootNodeflags会包含placement

EffectList是不会包含root节点的,所以需要将root节点也添加到EffectList,这样才会正确的执行placement,让DOM树在页面呈现 。


 let firstEffect;
 // 把根节点finishedWork也连接进去
 if (finishedWork.flags > PerformedWork) {
  if (finishedWork.lastEffect !== null) {
   finishedWork.lastEffect.nextEffect = finishedWork;
   firstEffect = finishedWork.firstEffect;
  } else {
   firstEffect = finishedWork;
  }
 } else {
  // 根节点没有effect.
  firstEffect = finishedWork.firstEffect;
 }

EffectList的遍历

EffectList的主要是用于Layout阶段生命周期方法的执行和DOM的操作。


// 处理getSnapshotBeforeUpdate,调度useEffect
nextEffect = firstEffect;
do {
 commitBeforeMutationEffects();
} while (nextEffect !== null);
// DOM操作
nextEffect = firstEffect;
do {
 commitMutationEffects(root, renderPriorityLevel);
} while (nextEffect !== null);
// 生命周期方法的执行
nextEffect = firstEffect;
do {
 commitLayoutEffects(root, lanes);
} while (nextEffect !== null);

在这Layout阶段的这3个方法里,会遍历nextEffect,每执行完一个,就重新指向firstEffect。Layout阶段具体操作就不细讲了。

总结

EffectList不是全局变量,只是在Fiber树创建过程中,一层层向上收集有effect的Fiber节点,最终的root节点就会收集到所有有effect到Fiber节点,我们就把这条包含effect节点的链表叫做EffectList。

由于收集的过程是深度优先,子级会先被收集,所以遍历的时候也会先操作子级,所以如果有面试官问子级和父级的生命周期或者useEffect谁先执行,就很清楚的知道会先执行子级操作了。

以上就是简单分析React中的EffectList的详细内容,更多关于React中的EffectList的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

简单分析React中的EffectList

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

详解React中Fragment的简单使用

这篇文章主要介绍了详解React中Fragment的简单使用,文中通过示例代码介绍的非常详细,对我们学习React有一定的帮助,感兴趣的小伙伴们可以参考一下
2022-11-13

python简单的分析文本

import collectionsimport re#读取tips.txt文件内容,type(mytips)=strwith open("tips.txt","r",encoding="utf-8") as tip: myt
2023-01-31

React中State的原理分析

这篇文章主要介绍了React中State的原理分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。问题:setState 到底是同步还是异步的?如果对 React 底层有一定了
2023-06-26

MySQL之架构简单分析

上图为MySQL的简易架构图,给您有一个大概的概念,下面我将为您进行进一步的分析。连接器:当连接MySQL数据库时,等待的将是MySQL服务端的连接器;连接器的职责是和客户端建立连接、获取权限、维持和管理连接。客户端连接命令一般是如下所示(建议:不要在命令中显
MySQL之架构简单分析
2014-12-17

Ajax 数据请求的简单分析

Ajax使用的关键对象是XmlHttpRequest对象,但是涉及到跨浏览器的的问题,所以,需要创建一个具兼容性的对象
2022-11-21

简单分析ARP协议中的基本IP地址

  地址解析协议,也就是ARP,是根据IP地址获取物理地址的一个TCP/IP协议。ARP命令可用于查询本机ARP缓存中IP地址和MAC地址的对应关系、添加或删除静态对应关系等。在这一篇教程里面,小编主要和大家简单的介绍一下:简单分析ARP协议中的基本IP地址。  对于网络的传输这一个来说的话,IP地址也就相当于主机地址
简单分析ARP协议中的基本IP地址
2024-04-18

React中的Virtual DOM示例分析

本篇内容主要讲解“React中的Virtual DOM示例分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“React中的Virtual DOM示例分析”吧!这是Choerodon的一个前端页面
2023-06-29

简单分析ICMP协议的重要性

  ICMP是(Internet Control Message Protocol)Internet控制报文协议。它是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。现在小编给大家带来的教程是:简单分析ICMP协议的重要性。  
简单分析ICMP协议的重要性
2024-04-18

如何进行IO流的简单分析

如何进行IO流的简单分析,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。IO流的分类:1、根据流的数据对象来分:高端流:所有的内存中的流都是高端流,比如:Inpu
2023-06-02

Python正则简单实例分析

本文实例讲述了Python正则简单用法。分享给大家供大家参考,具体如下: 悄悄打入公司内部UED的一个Python爱好者小众群,前两天一位牛人发了条消息: 小的测试题:re.split('(W+)', ' test, test, test.
2022-06-04

简单HCIA题库讲解分析

  简单hcia题库讲解分析:只需要笔试的华为认证HCIA难度会比较低,一般情况下,掌握了对应的知识点后,通过练习题库,通过的难度都不大,接下来编程学习网小编就来简单的讲解分析一下HCIA题库的相关内容。  简单HCIA题库举例  先来带大家看几道简答的HCIA题库里的题目。  1、Tracert诊断工具记录下每一个ICM
简单HCIA题库讲解分析
2024-04-18

简单解析ipv4地址分类

  IP地址简介  简单解析ipv4地址分类:基本的IP地址是分成8位一个单元(称为8 位位组)的32位二进制数。二进制与十进制大家都懂吧。为了方便人们的使用,对机器友好的二进制地址转变为人们更熟悉的十进制地址。IP地址中的每一个8位位组用0~255之间的一个十进制数表示。这些数之间用点(.)隔开,这是所谓的点-十进制
简单解析ipv4地址分类
2024-04-18

编程热搜

目录