〇背景
DOMからレンダリングまでをあらかたたどった上で、よーやっと今回でVueの機能について学べる。差分レンダリングはなんとなくわかるが、仮想DOMについてはいつ、どのタイミングで作られ、どのタイミングで擦り合わせられるのかが知りたい。しかし、それまでにはまだ他に知らねばならない工程がある。今回はそこを潰して噛み砕く。
〇今回のコード例
特になし
〇調べる前の自分の認識(検証)
「ブラウザで触っているのが仮想DOM? 触ると差分ができてDOMに反映? レンダリングは不可逆じゃないの?」
〇調べた結果(要点まとめ)
あの例え話を流用する。
まず木の絵(HTML,CSS)を描く人、そしてその絵を魔法の池(ブラウザ)に入れることで大樹(DOM)ができる。池の辺りには庭師(JSエンジン)がいて、庭師道具(DOMエンジン)を頼りに大樹をデザインする。この大樹を人間が見えるように加工する(レンダリング)
さあ、この概念を元に、仮想DOMやVueの概念を付け加える。
まず最初に絵を描く人がいた。これはつまりは設計書を作っていたが、その設計書を作るための、さらにその設計書がVueフレームワークということだ。
つまるところ、型のある要件書(Vue)を絵を描く人に伝える(ビルド)。そしてその後に池に入れた際に、最初に根っこの部分は実物が作られるが、全体が作られる前に庭師も下書きを作る。庭師の下書きが仮想DOMである。下書きの後に実際の木が作られる。
そして、ユーザが更新がする場合=木がユーザによって形を変えたい場合、庭師が最初にその要望を聞いて下書きを一から作り直す。そして昔の下書きと差分を確認し、差分のあるところだけ実際の木を変える。こう言う具合である!!
レンダリングは不可逆というより、そもそも可逆性が必要ない。
はい。では実際の知識をまとめてみよう。
仮想DOM(Virtual DOM / VNode)とは
- フレームワーク内部の“軽量DOMの設計図(木)”。実DOMを直接触る前に、「次にこういうDOMにしたい」を表現する中間表現。
-
生成タイミング
- 初回マウント:テンプレート/JSX→render関数→VNodes(仮想DOM) 作成
- 状態更新ごと:依存しているコンポーネントだけ再レンダして新しいVNodesを作る
- 役割:旧VNodes と 新VNodes を diffして、**最小の実DOM操作(patch)**を導き出す。
Vue と React の“性格の違い”(ざっくり)
- Vue 3:テンプレートをコンパイルして patch flags / block tree / static hoisting を使い、“変わり得る所だけ”を見る最適化が強い。更新は依存追跡で必要コンポーネントだけ再レンダ。
- React:JSX→renderで新ツリーを作成し、Fiberで優先度制御しつつdiff。Concurrent Featuresで割り込みや遅延も可能。
〇動作解説(図解・擬似フロー)
1) 初回マウント
状態(ref/store) ──→ render() ──→ 仮想DOM(VNodes) ──→ patch(実DOMを生成) ──→ 画面
2) 更新サイクル(差分レンダリング)
ユーザー操作/非同期完了 → 状態が変わる
↓(Vue: 依存追跡で該当コンポーネントに更新ジョブをスケジュール)
render() を再実行して「新しい仮想DOM」を生成
↓
旧VNodes と 新VNodes を diff(Reconciliation)
↓
差分だけ実DOMへ patch(属性変更/ノード追加削除/テキスト更新など)
↓
ブラウザが必要な工程だけ再実行(レイアウト/ペイント/合成)
3) 差分の具体
- 同じタグ & 同じ key → 属性/子だけ更新
- key が変わる → 別物として扱う(丸ごと作り直し)
- リストでは key が同一要素の識別子。これがないと並べ替え時に意図せぬ再作成が起きやすい
〇実務での注意点(チェックリスト)
A. 差分を“気持ちよく”させる
- key は安定IDを使う(indexは並べ替えに弱い)
- 大きい塊を毎回作り直さない:v-once、静的部分の切り出し、メモ化(computed / Reactなら memo)
- イベント/関数の再生成を抑える:Vueはそこまで神経質でなくてOKだが、巨大リストでは工夫(スロット/propsのshape安定化)
B. “直接DOMいじり”は最小限に
- 状態→UIの流れを優先(refやStoreを更新 → テンプレで反映)。
- 必要なら onMounted + nextTick や カスタムディレクティブで局所的に。
C. レンダリング負荷を抑える
- リストは仮想スクロール(大量1000件は可視範囲だけ描く)
- CSSで動かす:transform/opacity 優先(合成のみで済みやすい)
- 計算は computed:毎レンダで重い処理をしない
- watchよりcomputed(依存解決が自動・キャッシュされる)
D. Vue 3 の最適化を知っておく
- Patch Flags / Block Tree:テンプレートコンパイル時に「ここだけ動く」と印を付け、diff 範囲を縮小
- shallowRef / markRaw:大オブジェクトのリアクティブ化コストを避ける
- v-memo / v-once:再レンダを抑制
- Teleport / フラグメント:DOM構造上の都合を解決しつつ差分適用
〇まとめ・所感
- 差分レンダリング=前後のツリー差分だけ実DOMを変える設計。
- 仮想DOM=その差分を安全・高速に導くための“下書きの木”(ユーザーは触らない、フレームワーク内部)。
- Reconciliation=旧/新ツリーの“調停”。Vue も React もここで最小パッチを決める。
- 「レンダリングは不可逆?」→ 何度でも更新できる。DOMが変われば、ブラウザは必要な段だけ(レイアウト/ペイント/合成)をやり直す。
- 実務では key と“静的部分の固定化”、“状態→UI”の徹底、大規模UIは仮想スクロールあたりを押さえれば、差分レンダリングの強みを最大限享受できる。
レンダリングの最適化、差分更新の最適化など、実際にブラウザ上に載せた後の性能においてはいずれさらにここの知識が必要になると思う。とりあえず、どのような順序で画面が映り、そして切り替わっているのかの解像度が高まった。庭師が働きすぎな気がする。まあ良いよ。
ここら辺も掘り下げたいが、明らかに玄人になりそうなので、一回この一連の流れを整理する工程は終わりにする。次はどちらかというとビルドあたりの知識を知りたい。
設計書から移し替える工程で、まあ他の言語やフレームワークでもやっているわけだが、それをもうちょい噛み砕きたい。
例え話にしたがおぼえやすいんだあ!!