建議先備知識:DOM渲染原理
現代網頁複雜性越來越高,一個網頁的DOM Tree動轍幾百個節點,如果我們每次操作DOM,都要重新渲染頁面,那成本似乎有點太高了吧!於是就有人想出了Virtual DOM,在JS和DOM之間做一個緩衝,渲染之前先比較新舊DOM的差異,再只針對有變化的部分做DOM操作,如此就能解決重新渲染的成本問題。
所以Virtual DOM(虛擬DOM)是什麼?
Virtual DOM本質上就是一個JS物件,它是一種用JS物件描述DOM的方式
<div id="app">
<p class="text">hello world!!!</p>
</div>
上面的HTML會被React轉換為Virtual DOM(如下),就是一個JS物件
{
tag: 'div',
props: {
id: 'app'
},
chidren: [
{
tag: 'p',
props: {
className: 'text'
},
chidren: [
'hello world!!!'
]
}
]
}
Virtual DOM優點
- 跨平台,Virtual DOM並非一定要渲染成瀏覽器DOM,也可以渲染成Native App的元素,或是做SSR(服務器端渲染)
- 減少性能浪費,總是以最小成本進行更新。當狀態更動,透過Diff算法比較、找出差異,再更新到DOM Tree上
要注意的是,Virtual DOM的性能未必比直接操作DOM快,它的優點是在於,不管狀態怎麼變化,都能以最小成本來更新DOM
Virtual DOM運作流程
- 產生Virtual DOM
- 根據Virtual DOM產生Real DOM
- 當某事件被觸發,狀態(state)發生變化
- 產生新的Virtual DOM
- 比較新舊Virtual DOM差異(透過Diff算法)
- 把差異Patch到Real DOM上
圖片來源:https://medium.com/geekabyte/lets-better-know-the-famous-vdom-a21faf9e9157
React Diff算法簡介
Diff是diffrence的簡寫,目的在找出新舊Virtual DOM的差異,
一般的tree diff算法時間複雜度很高,而React的diff則制定了兩個假設來降低其複雜度
- 同層比對,當發現有一層有差異,表示往下的樹就不同
- 開發者可透過key prop來決定其子樹是否需要重新render
算法的細節比較複雜,如果想更深入了解可自行研究:
深度剖析:如何实现一个 Virtual DOM 算法
React 源码深度解读(十):Diff 算法详解
為什麼不建議用index當key?
大家應該知道React不建議在循環列表時使用index當key,為什麼?
這是因為我們的新舊Virtual DOM上的key必須要一致,才會提升Diff在比對時的效率,而使用index的話,就無法確保key一致了
舉個例子,假設有一個列表用index當key
<li key=0>a</li>
<li key=1>b</li>
<li key=2>c</li>
然後狀態更動 刪除a,就會變成
<li key=0>b</li>
<li key=1>c</li>
可以看到,b的key不相同了,這樣就無法建立關聯性,對性能上完全沒有幫助,
因此好的做法還是給其穩定、不變的key值
Reference:
從頭打造一個簡單的 Virtual DOM
虚拟 DOM 到底是什么?
https://zh-hant.reactjs.org/docs/reconciliation.html