React原理 – Virtual DOM
建議先備知識: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
