一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服務器之家 - 編程語言 - JavaScript - React - 簡單分析React中的EffectList

簡單分析React中的EffectList

2022-02-24 16:47zhangyu React

這篇文章主要簡單分析了React中的EffectList,幫助大家更好的理解和學習使用React進行前端開發,感興趣的朋友可以了解下

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。

簡化代碼如下。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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。

?
1
2
3
4
5
6
<div id="1">
 <div id="4"/>
 <div id="2">
  <div id="3"/>
 </div>
</div>

最終形成的EffectList為

?
1
2
firstEffect => div4
lastEffect => div1

因為Fiber樹的構建深度優先,所有div4先完成completeWork,構建firstEffect。

EffectList遍歷是從firstEffect開始,通過每一個節點的nextEffect找到下一個節點。

?
1
2
3
4
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樹在頁面呈現 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
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的操作。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 處理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的資料請關注服務器之家其它相關文章!

原文鏈接:https://juejin.cn/post/6947168516394975239

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: www.色香蕉 | 亚洲欧美一级夜夜爽w | 日本人泡妞xxxxxx69 | 欧美成人免费一区在线播放 | 日韩欧美一区二区在线 | 国产免费专区 | 歪歪动漫小说sss | 亚洲午夜精品久久久久久人妖 | 欧美日韩一区二区三区免费 | 国产午夜精品久久理论片 | 日本一区二区三区视频在线观看 | 五月天精品视频播放在线观看 | 九九在线免费视频 | 成人在线视频在线观看 | 成人福利在线观看 | 国产午夜亚洲精品一区网站 | 亚洲 色 欧美 爱 视频 日韩 | 国产成人精品一区 | 国产成人精品免费午夜 | 999精品视频在线 | 免费网址视频在线看 | 无码国产成人午夜在线观看不卡 | 日产乱码卡1卡2卡三卡四在线 | 国产一级大片免费看 | 国产亚洲视频在线 | 99视频免费 | 国产在线视频一区二区三区 | 精品久久久久久影院免费 | ai换脸杨幂被c在线观看 | 青青草原国产 | 韩国理论片最新第一页 | 厨房里摸着乳丰满在线观看 | 亚洲福利区 | 4虎影院永久地址www | 欧美一级二级片 | 日韩爱爱| 国产盗摄wc厕所撒尿视频 | 亚洲成人网在线 | 寡妇快点好大好爽视频 | asian4you裸模| 好逼天天有 |