2025年1月19日

ReactでVurtial DOMがどのようにActual DOMに変更をかけているのか

  • この記事の目的は、「Reactが内部でどういう流れで差分を検知し、Actual DOMに変更をかけているのか」を理解して、メンタルモデルを作るのを助けること。

  • Virtual DOM(vDOM)について

    • Virtual DOMとは、Actual DOMを軽量化してコピーしたものであり、JavaScript オブジェクトとしてモデル化されたHTMLドキュメントに過ぎない。Actual DOMはNode オブジェクトで構成されている。
    • Reactのコンポーネントがレンダリングされている間(Reconciliationプロセス)
    • 1.新しいVirtual DOM treeを作成
    • 2.古いVirtual DOM treeと新しいvDOMを比較
    • 3.最小の変化を計算して、古いVirtual DOMに新しく変化した箇所を適応させる

例1: カウンターコンポーネントが際レンダリングされるまで

JSXで書いたコンポーネント

// カウントするReactコンポーネント
function Counter() {
  const [count, setCount] = useState(0)
  return (
    <main>
      <div>
        <h1>hello world!!</h1>
        <div>クリック数: {count}</div>
        <button onClick={() => setCount(count + 1)}>クリック</button>
      </div>
    </main>
  )
}

JSXをcreateElementに置き換える

// JSXをcreateElementに置き換えると
function Counter() {
  const [count, setCount] = useState(0)

  return React.createElement(
    'main',
    null,
    React.createElement(
      'div',
      null,
      React.createElement('h1', null, 'hello world!!'),
      React.createElement('div', null, 'クリック数: ', count),
      React.createElement(
        'button',
        { onClick: () => setCount(count + 1) },
        'クリック'
      )
    )
  )
}

// React.createElementの引数について
// ・first arg: HTML tag name.
// ・second arg: an object of properties.
// ・any additional args represent child elements.

//レンダリング時のVirtual Dom Treeはこんな感じ
// 1.初回
// main
//  |- div
//     |- h1
//     |  |- 'hello world!!'
//     |- div
//     |  |- 'クリック数: 0'
//     |- button
//     |  |- 'クリック'

// 2.ボタンを1回クリック→ 再レンダリングしてdiv要素を更新
// main
//  |- div
//     |- h1
//     |  |- 'hello world!!'
//     |- div
//     |  |- 'クリック数: 1'
//     |- button
//     |  |- 'クリック'

ボタンをクリックして変化があったのはdiv要素のみなので、div要素のみ再計算されてActual DOMの一部を更新する。つまり、button要素は更新されない「レンダーは時間を切り取ってスナップショットを取る」と公式に書かれているのは、Vurtial DOM Treeが上記の振る舞いをするからだと言える。

例2: 本ブログサイトの記事一覧で考えてみる


ブログサイトの記事一覧画像 blog-cards-image


Virtual DOM Virtual-DOM-image


Actual DOM Actual-DOM-image


ユーザーが入力して記事をフィルタリング


1.SearchBarからstateを更新 blog-cards-image


2.Virtual DOMの更新 Virtual-DOM-during-updating


3.差分検知(Fiber Reconcilation) blog-cards-reconcilation


4.Actual DOMの一括更新 Actual-DOM-during-updating


5.フィルタリング結果 filterd-blog-cards-image


まとめ

  • Virtual DOMはただのJavaScriptオブジェクト
  • コンポーネントのレンダリングの流れ
    • 1.初回のレンダリング、setStateなどによって、Virtual DOMの作成がトリガーされる
    • 2.差分検知が行われて最小の更新範囲を計算して導き出す
    • 3.2で計算された最小の更新範囲をActual DOMに適用する
    • 4.適用されたDOMが画面で閲覧できるようになる

参照

Fluent React: Build Fast, Performant, and Intuitive Web Applications Node - Web API | MDN React Virtual DOM, Reconciliation and Fiber Reconciler state はスナップショットである