React Reconciliation
一.什么是Reconciliation
- 每次
render
的時候,React
都會產生一棵由React元素
組成的樹,這個樹形結構就是所謂的虛擬DOM
,下次render
的時候又會產生新的一顆樹,對比這兩棵樹的不同的過程,就是調和,即Reconciliation
二.對比過程,分為以下幾種情況
1. 根節點類型不同的情況
- 如果根節點就不同,如下的
div
變成了span
,那么對比的開銷太大了,所以React
選擇了重建,會將原有的樹卸載
,再將新的樹裝載
<div>
<Counter />
</div>
<span>
<Counter />
</span>
2.根節點類型相同的情況
如果是根節點相同的情況下,只會更改有變化的部分
當節點類型是HTML元素類型時(如
span,p,div
等)
如下,只會更改color
變化的值和div
里變化的值
<div style={{color: 'red', fontWeight: 'bold'}}>hello world</div>
<div style={{color: 'green', fontWeight: 'bold'}}>good bye</div>
-
當節點類型是React組件類型時
如下,
React
并不知道如何去更新DOM,因為這些邏輯還在React
組件當中,所以只能去更新props
的值,引發這個組件的更新過程,實現對子元素的遞歸<Todo text="old"> <Todo text="new">
3.多個同級元素的情況
- 有時候我們會遇到增加同級元素的情況,這里以HTML元素為例,
React
組件也是一樣 - 如果是在最下方插入的情況,那么事情沒那么糟糕,因為
React
會去對比每個元素,first
對比fisrt
,second
對比second
,然后發現多了一個third
,那么就在原有的基礎上加上這個元素 - 但是如果是在最上方插入的情況,
React
使用的O(n)
復雜度的算法會逐個對比,即first
對比third
,second
對比first
,然后發現多了一個second
,這樣的話,本來只是新增一個元素的情況,會變成全部元素都要修改
//最下方插入
<ul>
<li>first</li>
<li>second</li>
</ul>
<ul>
<li>first</li>
<li>second</li>
<li>third</li>
</ul>
//最上方插入
<ul>
<li>first</li>
<li>second</li>
</ul>
<ul>
<li>third</li>
<li>first</li>
<li>second</li>
</ul>
- 有沒有解決上面最上方插入所帶來的問題的方法呢,答案是使用唯一的
Key
- 當使用了唯一的
Key
以后,React
會知道,first
和second
是原來的那個元素,現在新增的只是third
元素,當然這里有很重要的一點,這個Key
必須是穩定不變的,試想一下,如果原先first
是1,second
是2,后面third
是1,first
是2,second
是3,這樣的話,從上到下一一對比,每個元素又要重新渲染,就失去了Key
的意義,導致不必要的元素重新創建和子組件中的狀態丟失【1】
//最上方插入
<ul>
<li key={1}>first</li>
<li key={2}>second</li>
</ul>
<ul>
<li key={0}>third</li>
<li key={1}>first</li>
<li key={2}>second</li>
</ul>
三.代碼優化思考
1.以前早就聽說過不要用數組下標作為Key
,但是現在才對Key
值需要唯一且穩定有了深刻理解,具體理解見上面的【1】,數組下標作為Key
也不是一棒子打死,當這些元素不需要重新排序的時候,可以采用,當這個元素需要重新排序的時候,就不要用數組下標了
2.也不要用Math.random()
作為Key
3..針對React
對根節點類型不同的情況的處理,在寫代碼的時候就要避免改變根節點的情況