KAKUTA TECH BLOG

Blog Article

React の仮想 DOM を基礎から理解する

はじめに

React を学習していると、「仮想 DOM(Virtual DOM)」という言葉を必ず目にします。

JavaScript では DOM を直接操作して HTML 要素を取得し、アニメーションを付けたり、内容を書き換えたりできますが、「仮想 DOM が何なのか」「なぜ必要なのか」が分からず、なんとなく使っている人も多いのではないでしょうか。

この記事では、プログラミング初学者の方でも理解できるように、仮想 DOM の仕組みを基礎から丁寧に説明します。

さらに、React が高速に画面を更新できる理由である diff と patch、レンダリングの流れ、仮想 DOM がいつ・どのように更新されるのかまで、順を追って解説していきます。

参考にしたリンク

仮想 DOM とは何か

仮想 DOM とは、「ブラウザに表示されている本物の DOM を直接操作せず、まずメモリ上に仮想的な DOM を作って更新する仕組み」のことです。

一言で言うなら、「画面の設計図をメモリ上に持っておき、差分だけを本物の画面に反映するための仕組み」です。

React は、画面を更新するたびに直接 DOM を触るのではなく、「今どんな UI を表示したいか」という情報を JavaScript のオブジェクトとして保持します。このオブジェクトの集合が、一般に仮想 DOM と呼ばれています。

仮想 DOM が必要な理由

仮想 DOM が必要な理由を一言で表すなら、「DOM 操作を最小限に抑えるため」です。

もし仮想 DOM がなかった場合、React は state が変わるたびに「どこを更新すべきか」を開発者が自分で管理する必要があります。

これはコードが複雑になり、バグの原因にもなります。

仮想 DOM があることで、開発者は「どう表示したいか」だけを書けばよく、更新の最適化は React が自動で行ってくれます。

なぜ本物の DOM を直接操作しないのか

ブラウザの DOM は、画面に直接影響を与える存在です。そのため、DOM を変更すると、ブラウザは次のような処理を行います。

  • レイアウトの再計算
  • スタイルの再適用
  • 再描画

これらはすべてコストの高い処理です。要素が多い画面で DOM 操作を頻繁に行うと、動作が重くなり、カクつきや遅延の原因になります。

仮想 DOM は何が違うのか

仮想 DOM は、ただの JavaScript オブジェクトです。

メモリ上のデータなので、更新や比較が非常に高速です。

React はまずこの軽いデータ構造を更新し、前回の状態と比較して「どこが変わったのか」だけを調べます。そして、必要最小限の変更だけを本物の DOM に反映します。

仮想 DOM の基本的な流れ

仮想 DOM を使った React の画面更新は、次のような流れで行われます。

あなたのコード
↓
仮想 DOM を生成・更新
↓
前回の仮想 DOM と比較(diff)
↓
必要な部分だけを実 DOM に反映(patch)

この仕組みによって、React は無駄な DOM 操作を避けながら、効率よく UI を更新できます。

diff と patch とは何か

diff とは、「前回の仮想 DOM と新しい仮想 DOM を比較し、どこが変わったのかを特定する処理」です。

一言で言うなら、「変更点を見つける作業」です。

React は仮想 DOM を木構造として扱い、タグの種類、属性、テキスト、子要素などを順番に比較していきます。

patch とは、diff によって見つかった差分を「実際の DOM に反映する処理」です。

diff が「何が変わったか」を調べるのに対し、patch は「その変更を画面に反映する」役割を担います。

diff と patch は必ずセットで動きます。

  • diff:変更点を洗い出す
  • patch:その変更点だけを実 DOM に適用する

この分業によって、React は高速な画面更新を実現しています。

React の diff アルゴリズム

React はすべての要素を完全に比較しているわけではありません。

現実的な速度を保つために、いくつかのルールを設けています。

  1. 同じ型の要素は同じものとして扱う

    <div><div> のままであれば、React は「同じ要素」と判断し、中身だけを比較します。

    一方で、<div><span> に変わると、要素そのものが別物とみなされ、作り直されます。

  2. 子要素は基本的に順番で比較する

    React はリスト要素を位置ベースで比較します。

    そのため、並び順が変わると不要な再生成が起きやすくなります。

  3. key がある場合は key で比較する

    key を指定すると、React は「同じ key を持つ要素は同一」と判断します。

    これにより、リストの並び替えでも正しく差分を計算できます。

diff の具体的なイメージ

たとえば、次のような変更があったとします。

前の仮想 DOM:

<h1>こんにちは</h1>

新しい仮想 DOM:

<h1>こんばんは</h1>

diff の結果として、React は次のように判断します。

  • <h1> 要素は同じ
  • テキストだけが変更されている

そのため patch では、<h1> のテキスト部分だけが書き換えられます。

仮想 DOM はいつ更新されるのか

仮想 DOM は、「再レンダーが発生したとき」に更新されます。

React では、次のような場合に再レンダーが起こります。

  • state が更新されたとき
  • props が変更されたとき

再レンダーとは、「新しい UI の説明書を作り直すこと」です。

レンダリングフェーズとコミットフェーズ

React の画面更新は、次の 2 つのフェーズに分かれています。

フェーズ

内容

Render フェーズ

新しい仮想 DOM を作る

Commit フェーズ

差分を実 DOM に反映する

仮想 DOM が作られるのは Render フェーズです。その後に diff と patch が行われます。

React は前回の仮想 DOM を保持している?

React は内部に Fiber と呼ばれるデータ構造を持っており、前回のレンダー結果を保持しています。これが「前回の仮想 DOM」に相当します。

差分を計算するためには、「前」と「後」の状態が必要です。そのため、React は常に前回の情報を保持しています。

実 DOM はあくまで描画結果であり、React にとっての本当の状態は Fiber ツリーです。

仮想 DOM を作るために必要な情報

  • コンポーネントの state
  • 親から渡された props
  • JSX による UI の定義

これらをもとに、「今この瞬間の UI」を表す仮想 DOM が作られます。

diff を行うために必要な情報

  • 前回の仮想 DOM
  • 今回の仮想 DOM
  • 差分を計算するルール

これらを使って、React は最小限の更新箇所を特定します。

まとめ

  • 仮想 DOM は UI の状態を表す軽量なデータ構造です
  • 本物の DOM を直接操作せず、差分だけを反映します
  • diff は変更点を見つける処理です
  • patch は差分を実 DOM に適用する処理です
  • 仮想 DOM は再レンダー時に必ず作り直されます

仮想 DOM の仕組みを理解すると、React が「なぜ速いのか」「なぜ書きやすいのか」がはっきり見えてきます。

内部の動きを意識しながらコードを書くことで、より良いコンポーネント設計やパフォーマンス改善につなげることができるでしょう。