六. React的一致性比較(Reconciliation)(Setstate時(shí)執(zhí)行了什么)

動(dòng)機(jī)

當(dāng)使用React時(shí),在下一個(gè)steate或props更新時(shí),render()函數(shù)將會(huì)返回一個(gè)不同的React樹,接下來(lái)React會(huì)找出最高效地方式更新UI。
目前存在大量通用的方法能夠以最少的操作步驟將一個(gè)樹轉(zhuǎn)化成另外一棵樹。然而,這個(gè)算法是復(fù)雜度為O(n3),其中n 為樹中元素的個(gè)數(shù)。即如果有1000個(gè)元素,那么每次更新都要進(jìn)行10億次比較。
然而,React給予一下兩個(gè)假設(shè)實(shí)現(xiàn)了復(fù)雜度為O(n)的算法,即每次更新只需要進(jìn)行1000次的比較:

  1. 不同類型的兩個(gè)元素將會(huì)產(chǎn)生不同的樹。
  2. 開發(fā)人員可以使用一個(gè) key prop 來(lái)指示在不同的渲染中那個(gè)那些元素可以保持穩(wěn)定。

一. Diffing 算法

當(dāng)比較不同的兩個(gè)樹的時(shí)候,React首先比較兩個(gè)根元素。根據(jù)根元素的類型,他有不同的行為。

1.1 元素類型不相同

無(wú)論什么時(shí)候,當(dāng)根元素類型不同時(shí),React將會(huì)銷毀原先的樹并重新構(gòu)建新的樹。
當(dāng)銷毀原先的樹時(shí),之前的DOM節(jié)點(diǎn)將全部被銷毀。組件會(huì)執(zhí)行componentWillUnmount()。當(dāng)構(gòu)建新的樹時(shí),新DOM節(jié)點(diǎn)將會(huì)插入DOM中。組件將會(huì)執(zhí)行componentWillMount() 以及 componentDidMount() 。與之前舊的樹相關(guān)的 state 都會(huì)丟失。

1.2 DOM元素類型相同

當(dāng)比較兩個(gè)相同類型的 React DOM 元素時(shí),React 檢查它們的屬性(attributes),保留相同的底層 DOM 節(jié)點(diǎn),只更新反生改變的屬性(attributes)。
當(dāng)處理完當(dāng)前DOM節(jié)點(diǎn)后,React會(huì)遞歸處理子節(jié)點(diǎn)。

1.3 相同類型的組件

當(dāng)一個(gè)組件更新的時(shí)候,組件實(shí)例保持不變,以便在渲染中保持state。React會(huì)更新組件實(shí)例的屬性來(lái)匹配新的元素,并在元素實(shí)例上調(diào)用 componentWillReceiveProps()componentWillUpdate()

1.4 子元素遞歸

例如,當(dāng)給子元素末尾添加一個(gè)元素,在兩棵樹之間轉(zhuǎn)化中性能就不錯(cuò):

<ul>
  <li>first</li>
  <li>second</li>
</ul>

<ul>
  <li>first</li>
  <li>second</li>
  <li>third</li>
</ul>

React 會(huì)比較兩個(gè) <li>first</li> 樹與兩個(gè) <li>second</li> 樹,然后插入 <li>third</li> 樹。

如果在開始處插入一個(gè)節(jié)點(diǎn)也是這樣簡(jiǎn)單地實(shí)現(xiàn),那么性能將會(huì)很差。例如,在下面兩棵樹的轉(zhuǎn)化中性能就不佳。

<ul>
  <li>Duke</li>
  <li>Villanova</li>
</ul>

<ul>
  <li>Connecticut</li>
  <li>Duke</li>
  <li>Villanova</li>
</ul>

React 將會(huì)改變每一個(gè)子節(jié)點(diǎn)而沒有意識(shí)到需要保留 <li>Duke</li> 和 <li>Villanova</li> 兩個(gè)子樹。這種低效是一個(gè)問(wèn)題。

1.5 Keys

React提供了一個(gè)key屬性(attributes)。當(dāng)節(jié)點(diǎn)有了key,React使用key去比較原來(lái)的書的子節(jié)點(diǎn)和之后的節(jié)點(diǎn)。當(dāng)我們添加一個(gè)key時(shí),可以是上面抵消的例子轉(zhuǎn)換變高效:

<ul>
  <li key="2015">Duke</li>
  <li key="2016">Villanova</li>
</ul>

<ul>
  <li key="2014">Connecticut</li>
  <li key="2015">Duke</li>
  <li key="2016">Villanova</li>
</ul>

此時(shí)React知道只有'2014'key的元素是新的,剩下的兩個(gè)元素僅僅只是被移動(dòng)而已。這樣就會(huì)保留剩下的兩個(gè)元素只更新新加入的元素。

1.6 總結(jié)

因?yàn)镽eact依賴這兩個(gè)啟發(fā)式,如果背后的假設(shè)沒有得到滿足,性能將會(huì)受到影響。

  1. 算法不會(huì)嘗試匹配不同節(jié)點(diǎn)類型的子樹。
  2. keys應(yīng)該是穩(wěn)定的,可預(yù)測(cè)的并且是唯一的。不穩(wěn)定的 key (類似于 Math.random() 函數(shù)的結(jié)果)可能會(huì)產(chǎn)生非常多的組件實(shí)例并且 DOM 節(jié)點(diǎn)也會(huì)非必要性的重新創(chuàng)建。這將會(huì)造成極大的性能損失和組件內(nèi)state的丟失
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 參考文章:深度剖析:如何實(shí)現(xiàn)一個(gè)Virtual DOM 算法 作者:戴嘉華React中一個(gè)沒人能解釋清楚的問(wèn)題——...
    waka閱讀 6,147評(píng)論 0 21
  • 3. JSX JSX是對(duì)JavaScript語(yǔ)言的一個(gè)擴(kuò)展語(yǔ)法, 用于生產(chǎn)React“元素”,建議在描述UI的時(shí)候...
    pixels閱讀 2,979評(píng)論 0 24
  • 我不建議每天熬夜到超過(guò)12點(diǎn)的,我也有過(guò)這樣一段時(shí)間,可是結(jié)果卻不好,每天腦袋昏昏沉沉,或許有的人認(rèn)為自己這樣是勤...
    張莫蠻閱讀 3,405評(píng)論 8 85
  • 每天早上到單位先思考一下今天的安排,有要干的工作,也有需要料理得家事,提筆簡(jiǎn)單羅列一二,似乎有了努力的目標(biāo),...
    青松樂(lè)悠閱讀 159評(píng)論 0 0

友情鏈接更多精彩內(nèi)容