亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

簡(jiǎn)單分析React中的EffectList

 更新時(shí)間:2021年04月07日 10:15:28   作者:zhangyu  
這篇文章主要簡(jiǎn)單分析了React中的EffectList,幫助大家更好的理解和學(xué)習(xí)使用React進(jìn)行前端開發(fā),感興趣的朋友可以了解下

React中,會(huì)遍歷EffectList來(lái)執(zhí)行節(jié)點(diǎn)操作、生命周期方法、Effect方法,可以把EffectList比作圣誕樹上掛的彩燈,而這顆圣誕樹就是Fiber樹。

為什么會(huì)存在EffectList呢?打個(gè)比方來(lái)說(shuō),一顆Fiber樹中有一些Fiber節(jié)點(diǎn)需要執(zhí)行componentDidMount方法,如果在Fiber樹構(gòu)建完成后,再遍歷一次Fiber樹,找到需要執(zhí)行componentDidMount方法的Fiber節(jié)點(diǎn),這是非常低效的。

而EffectList就解決了這個(gè)問(wèn)題,在Fiber樹構(gòu)建過(guò)程中,每當(dāng)一個(gè)Fiber節(jié)點(diǎn)的flags字段不為NoFlags時(shí)(代表需要執(zhí)行副作用),就把該Fiber節(jié)點(diǎn)添加到EffectList,在Fiber樹構(gòu)建完成后,由Fiber節(jié)點(diǎn)串成的彩燈也構(gòu)建完成了,這樣僅僅需要遍歷彩燈就行了。

EffectList的收集

EffectList是一個(gè)單向鏈表,firstEffect代表鏈表中的第一個(gè)Fiber節(jié)點(diǎn),lastEffect代表鏈表中的最后一個(gè)Fiber節(jié)點(diǎn)。

Fiber樹的構(gòu)建是深度優(yōu)先的,也就是先向下構(gòu)建子級(jí)Fiber節(jié)點(diǎn),子級(jí)節(jié)點(diǎn)構(gòu)建完成后,再向上構(gòu)建父級(jí)Fiber節(jié)點(diǎn),所以EffectList中總是子級(jí)Fiber節(jié)點(diǎn)在前面。

Fiber節(jié)點(diǎn)構(gòu)建完成的操作執(zhí)行在completeUnitOfWork方法,在這個(gè)方法里,不僅會(huì)對(duì)節(jié)點(diǎn)完成構(gòu)建,也會(huì)將有flags的Fiber節(jié)點(diǎn)添加到EffectList。

簡(jiǎn)化代碼如下。

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構(gòu)建
  if (
   returnFiber !== null &&
   (returnFiber.flags & Incomplete) === NoFlags
  ) {
   // 層層拷貝
   if (returnFiber.firstEffect === null) {
    returnFiber.firstEffect = completedWork.firstEffect;
   }
   if (completedWork.lastEffect !== null) {
    // 說(shuō)明當(dāng)前節(jié)點(diǎn)是兄弟節(jié)點(diǎn),子節(jié)點(diǎn)有effect,已經(jīng)給returnFiber.lastEffect賦值過(guò)了
    if (returnFiber.lastEffect !== null) {
     // 連接兄弟節(jié)點(diǎn)的effect
     returnFiber.lastEffect.nextEffect = completedWork.firstEffect;
    }
    returnFiber.lastEffect = completedWork.lastEffect;
   }
   
   const flags = completedWork.flags;
   
   // 該fiber節(jié)點(diǎn)有effect
   if (flags > PerformedWork) {
    // 當(dāng)前節(jié)點(diǎn)有effect連接上effect list
    if (returnFiber.lastEffect !== null) {
     returnFiber.lastEffect.nextEffect = completedWork;
    } else {
     // returnFiber沒(méi)有firstEffect的情況是第一次遇見(jiàn)有effect的節(jié)點(diǎn)
     returnFiber.firstEffect = completedWork;
    }
    returnFiber.lastEffect = completedWork;
   }
  }

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

EffectList實(shí)際是像冒泡一樣,一層一層不斷向上層收集,從第一個(gè)有flags的節(jié)點(diǎn)開始記錄,每層的新節(jié)點(diǎn)都會(huì)將上一個(gè)節(jié)點(diǎn)的firstEffectlastEffect拷貝到自身身上,再供上層節(jié)點(diǎn)再次拷貝。

如以下結(jié)構(gòu),假如每一個(gè)div都有flags。

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

最終形成的EffectList為

firstEffect => div4
lastEffect => div1

因?yàn)镕iber樹的構(gòu)建深度優(yōu)先,所有div4先完成completeWork,構(gòu)建firstEffect

EffectList遍歷是從firstEffect開始,通過(guò)每一個(gè)節(jié)點(diǎn)的nextEffect找到下一個(gè)節(jié)點(diǎn)。

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

初次Render時(shí)的EffectList

在React中,會(huì)對(duì)初次Mount有一個(gè)性能優(yōu)化,其中的Fiber節(jié)點(diǎn)的flags不會(huì)包含placement,對(duì)應(yīng)的DOM節(jié)點(diǎn)不會(huì)遍歷加入DOM樹,而是在創(chuàng)建DOM節(jié)點(diǎn)時(shí)就已經(jīng)加入DOM樹了,只有rootFiber節(jié)點(diǎn)FiberRootNodeflags會(huì)包含placement。

EffectList是不會(huì)包含root節(jié)點(diǎn)的,所以需要將root節(jié)點(diǎn)也添加到EffectList,這樣才會(huì)正確的執(zhí)行placement,讓DOM樹在頁(yè)面呈現(xiàn) 。

 let firstEffect;
 // 把根節(jié)點(diǎn)finishedWork也連接進(jìn)去
 if (finishedWork.flags > PerformedWork) {
  if (finishedWork.lastEffect !== null) {
   finishedWork.lastEffect.nextEffect = finishedWork;
   firstEffect = finishedWork.firstEffect;
  } else {
   firstEffect = finishedWork;
  }
 } else {
  // 根節(jié)點(diǎn)沒(méi)有effect.
  firstEffect = finishedWork.firstEffect;
 }

EffectList的遍歷

EffectList的主要是用于Layout階段生命周期方法的執(zhí)行和DOM的操作。

// 處理getSnapshotBeforeUpdate,調(diào)度useEffect
nextEffect = firstEffect;
do {
 commitBeforeMutationEffects();
} while (nextEffect !== null);
// DOM操作
nextEffect = firstEffect;
do {
 commitMutationEffects(root, renderPriorityLevel);
} while (nextEffect !== null);
// 生命周期方法的執(zhí)行
nextEffect = firstEffect;
do {
 commitLayoutEffects(root, lanes);
} while (nextEffect !== null);

在這Layout階段的這3個(gè)方法里,會(huì)遍歷nextEffect,每執(zhí)行完一個(gè),就重新指向firstEffect。Layout階段具體操作就不細(xì)講了。

總結(jié)

EffectList不是全局變量,只是在Fiber樹創(chuàng)建過(guò)程中,一層層向上收集有effect的Fiber節(jié)點(diǎn),最終的root節(jié)點(diǎn)就會(huì)收集到所有有effect到Fiber節(jié)點(diǎn),我們就把這條包含effect節(jié)點(diǎn)的鏈表叫做EffectList。

由于收集的過(guò)程是深度優(yōu)先,子級(jí)會(huì)先被收集,所以遍歷的時(shí)候也會(huì)先操作子級(jí),所以如果有面試官問(wèn)子級(jí)和父級(jí)的生命周期或者useEffect誰(shuí)先執(zhí)行,就很清楚的知道會(huì)先執(zhí)行子級(jí)操作了。

以上就是簡(jiǎn)單分析React中的EffectList的詳細(xì)內(nèi)容,更多關(guān)于React中的EffectList的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 從零開始學(xué)習(xí)搭建React腳手架項(xiàng)目

    從零開始學(xué)習(xí)搭建React腳手架項(xiàng)目

    這篇文章主要介紹了從零開始學(xué)習(xí)搭建React腳手架項(xiàng)目,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-08-08
  • React開啟代理的2種實(shí)用方式

    React開啟代理的2種實(shí)用方式

    最近有不少伙伴詢問(wèn)react的代理配置,自己也去試驗(yàn)了一下發(fā)現(xiàn)不少的問(wèn)題,在這就將所遇到的心得分享出來(lái),這篇文章主要給大家介紹了關(guān)于React開啟代理的2種實(shí)用方式的相關(guān)資料,需要的朋友可以參考下
    2021-07-07
  • React Native使用fetch實(shí)現(xiàn)圖片上傳的示例代碼

    React Native使用fetch實(shí)現(xiàn)圖片上傳的示例代碼

    本篇文章主要介紹了React Native使用fetch實(shí)現(xiàn)圖片上傳的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • 深入分析React源碼中的合成事件

    深入分析React源碼中的合成事件

    合成事件不是瀏覽器本身觸發(fā)的事件,自己創(chuàng)建和觸發(fā)的事件。本文將從源碼角度帶大家一起深入了解下React中的合成事件,需要的可以參考一下
    2022-11-11
  • 使用React實(shí)現(xiàn)內(nèi)容滑動(dòng)組件效果

    使用React實(shí)現(xiàn)內(nèi)容滑動(dòng)組件效果

    這篇文章主要介紹了使用React實(shí)現(xiàn)一個(gè)內(nèi)容滑動(dòng)組件效果,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-05-05
  • React利用scheduler思想實(shí)現(xiàn)任務(wù)的打斷與恢復(fù)

    React利用scheduler思想實(shí)現(xiàn)任務(wù)的打斷與恢復(fù)

    這篇文章主要為大家詳細(xì)介紹了React如何利用scheduler思想實(shí)現(xiàn)任務(wù)的打斷與恢復(fù),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以參考一下
    2024-03-03
  • TypeScript在React中的應(yīng)用技術(shù)實(shí)例解析

    TypeScript在React中的應(yīng)用技術(shù)實(shí)例解析

    這篇文章主要為大家介紹了TypeScript在React中的應(yīng)用技術(shù)實(shí)例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • React跨端動(dòng)態(tài)化之從JS引擎到RN落地詳解

    React跨端動(dòng)態(tài)化之從JS引擎到RN落地詳解

    這篇文章主要為大家介紹了React跨端動(dòng)態(tài)化之從JS引擎到RN落地,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • react16.8.0以上MobX在hook中的使用方法詳解

    react16.8.0以上MobX在hook中的使用方法詳解

    這篇文章主要為大家介紹了react16.8.0以上MobX在hook中的使用方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • React-View-UI組件庫(kù)封裝Loading加載中源碼

    React-View-UI組件庫(kù)封裝Loading加載中源碼

    這篇文章主要介紹了React-View-UI組件庫(kù)封裝Loading加載樣式,主要包括組件介紹,組件源碼及組件測(cè)試源碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06

最新評(píng)論