首页前端开发JavaScript简单分析React中的EffectList

简单分析React中的EffectList

时间2024-02-01 07:48:02发布访客分类JavaScript浏览1026
导读:收集整理的这篇文章主要介绍了简单分析React中的EffectList,觉得挺不错的,现在分享给大家,也给大家做个参考。 目录EffectList的收集初次Render时的EffectL...
收集整理的这篇文章主要介绍了简单分析React中的EffectList,觉得挺不错的,现在分享给大家,也给大家做个参考。
目录
  • EffectList的收集
  • 初次Render时的EffectList
  • 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 =>
     div4lastEffect =>
     div1

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

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

firstEffect =>
     div4div4.nextEffect =>
     div3div3.nextEffect =>
     div2div2.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,调度useEffectnextEffect = 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的资料请关注其它相关文章!

您可能感兴趣的文章:
  • 使用hooks写React组件需要注意的5个地方
  • React+Ant Design开发环境搭建的实现步骤
  • Vite搭建React项目的方法步骤
  • react获取input输入框的值的方法示例
  • react实现Radio组件的示例代码
  • React Router 如何使用history跳转的实现
  • 聊一聊我对 React Context 的理解以及应用
  • react hooks入门详细教程
  • 使用 React 和 Threejs 创建一个VR全景项目的过程详解

声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!

React

若转载请注明出处: 简单分析React中的EffectList
本文地址: https://pptw.com/jishu/595120.html
ADO.NET 连接数据库字符串小结(Oracle、SqlServer、Access、ODBC) .NET Framework 4.5新特性介绍

游客 回复需填写必要信息