React - 理解Virtual DOM


Posted by Andy Tsai on 2020-05-20

建議先備知識: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運作流程

  1. 產生Virtual DOM
  2. 根據Virtual DOM產生Real DOM
  3. 當某事件被觸發,狀態(state)發生變化
  4. 產生新的Virtual DOM
  5. 比較新舊Virtual DOM差異(透過Diff算法)
  6. 把差異Patch到Real DOM上


圖片來源:https://medium.com/geekabyte/lets-better-know-the-famous-vdom-a21faf9e9157

React Diff算法簡介

Diff是diffrence的簡寫,目的在找出新舊Virtual DOM的差異,

一般的tree diff算法時間複雜度很高,而React的diff則制定了兩個假設來降低其複雜度

  1. 同層比對,當發現有一層有差異,表示往下的樹就不同
  2. 開發者可透過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


#React #virtual dom #w3HexSchool #虛擬DOM







Related Posts

Host Environments & Reconciler

Host Environments & Reconciler

MTR04_0902

MTR04_0902

[心得] 滑鼠們

[心得] 滑鼠們



Comments