仮想 DOM
実際の DOM の軽量なコピーをメモリ上に保持し、差分だけを効率的に更新する仕組み
フロントエンドReact
仮想 DOM とは
仮想 DOM (Virtual DOM) は、実際の DOM の軽量な JavaScript オブジェクトのコピーをメモリ上に保持し、状態変更時に新旧の仮想 DOM を比較 (diff) して、差分だけを実際の DOM に反映する仕組みである。React が 2013 年に普及させた。
なぜ必要か
DOM 操作はブラウザで最もコストの高い処理の 1 つ。
直接 DOM 操作:
状態変更 → DOM 全体を再構築 → レイアウト再計算 → 再描画 (遅い)
仮想 DOM:
状態変更 → 仮想 DOM を再構築 (メモリ上、高速)
→ 新旧の仮想 DOM を比較 (diff)
→ 差分だけ実際の DOM に反映 (最小限の操作)
仮想 DOM の仕組み
// 仮想 DOM ノード (単なる JavaScript オブジェクト)
const vdom = {
type: 'div',
props: { className: 'card' },
children: [
{ type: 'h1', props: {}, children: ['Hello'] },
{ type: 'p', props: {}, children: ['World'] },
],
};
1. 状態変更 → render() で新しい仮想 DOM ツリーを生成
2. 新旧の仮想 DOM を比較 (Reconciliation)
3. 差分を計算 (例: テキストが "Hello" → "Hi" に変更)
4. 差分だけ実際の DOM に適用 (textContent = "Hi")
React の Reconciliation アルゴリズム
React は仮想 DOM の差分を検出する際、異なる型の要素はツリー全体を再構築し、同じ型の要素は属性の差分だけを更新する。リストでは key で要素を識別し、移動・追加・削除を最小化する。
// ❌ key がないとリスト全体を再レンダリング
{items.map(item => <li>{item.name}</li>)}
// ✅ key で要素を識別し、差分だけ更新
{items.map(item => <li key={item.id}>{item.name}</li>)}
仮想 DOM を使わないフレームワーク
| フレームワーク | アプローチ |
|---|---|
| React | 仮想 DOM + diff |
| Svelte | コンパイル時に直接 DOM 操作コードを生成 |
| SolidJS | Fine-grained reactivity (シグナル) |
| Vue | 仮想 DOM + コンパイラ最適化 |
Svelte や SolidJS は仮想 DOM を使わず、コンパイル時に最適な DOM 操作コードを生成する。仮想 DOM の diff コストがゼロになるため、理論上はより高速だ。
React Server Components と仮想 DOM
React Server Components はサーバーで仮想 DOM を生成し、シリアライズしてクライアントに送信する。クライアントでは JavaScript のバンドルサイズが削減される。
パフォーマンスの注意点
仮想 DOM は「DOM 操作を最小化する」が、「仮想 DOM の diff 自体」にもコストがある。不要な再レンダリングを防ぐために React.memo、useMemo、useCallback を適切に使う。
仮想 DOM の背景や設計思想は関連書籍に詳しい。