【実務・中級編】 Reactの差分検出アルゴリズム(Reconciliation) – React実践ガイド

Reactの「差分検出アルゴリズム(Reconciliation)」の正体:なぜReactは爆速なのか?

フロントエンド開発の現場で「仮想DOMが速い」という言葉を鵜呑みにしていませんか?
実は、仮想DOMそのものが魔法のように速いわけではありません。真の凄みは、Reactが裏側で行っている「Reconciliation(再帰的差分検出アルゴリズム)」という、ある種の泥臭いまでの最適化戦略にあります。

今日は、中級エンジニアの皆さんが明日からの設計に活かせるよう、ReactがDOMをどう比較し、なぜ計算量を抑え込んでいるのか、その深淵を紐解いていきましょう。

—

1. O(n³) から O(n) への奇跡

Reactの差分検出アルゴリズムを語る上で欠かせないのが、「2つのツリーを比較する」という問題の計算量です。

単純に2つのツリーを比較して最短の編集手順を見つけ出すアルゴリズムを素直に実装すると、その計算量は $O(n^3)$ になってしまいます。1,000個の要素があれば、10億回の比較が必要になる。これではブラウザは一瞬でフリーズします。

そこでReactは、現実的なアプリケーション開発のために、「2つの仮定」を置くことで計算量を $O(n)$ まで劇的に引き下げました。

1. 異なる型の要素は、異なるツリーを作る(例: `

` から `` に変わったら、中身は見ずに全部作り直す)。
2. `key` プロパティを使うことで、レンダリング間でどの要素が安定しているかを示せる。

この「割り切り」こそが、Reactの圧倒的なパフォーマンスの源泉です。

—

2. 現場で意識すべき「 Reconciliation」の挙動

Reactは親から子へ、再帰的にツリーを探索します。ここで最も気をつけなければならないのが、リストレンダリング時の `key` の扱いです。

なぜ `key` にインデックスを使ってはいけないのか?

多くの初心者がやりがちな「`key={index}`」という罠。これは Reconciliation において致命的なパフォーマンス低下を招くことがあります。

// 悪い例: keyにindexを使用(要素の挿入・削除で不整合が起きる)
{items.map((item, index) => (

))}

もし配列の先頭に新しい要素を追加した場合、インデックスがすべてズレるため、Reactは「すべての要素が変更された」と誤認し、DOMの再構築を強行します。本来なら「1つ追加されただけ」なのに、全要素を再描画する。これが「なぜか画面がカクつく」原因の正体です。

—

3. 実践:差分検出を最適化するコード設計

Reactの差分検出を味方につけるには、「不要な比較をさせない」ことが鉄則です。以下のコードで、Reactがどう判断を下すかの勘所を掴んでください。

import React, { useState, memo } from ‘react’;

// memo化することで、Propsの比較(浅い比較)をスキップさせ
// Reconciliationのプロセス自体を未然に防ぐ
const Child = memo(({ data }) => {
console.log(“Childがレンダリングされました”);
return

  • {data}
  • ;
    });

    export const ListComponent = () => {
    const [items, setItems] = useState([
    { id: ‘a1’, text: ‘React’ },
    { id: ‘b2’, text: ‘TypeScript’ }
    ]);

    const addItem = () => {
    // 安定したIDをkeyに使うことで、Reactは「既存のDOMを再利用すべき」と判断する
    setItems([{ id: ‘c3’, text: ‘Next.js’ }, …items]);
    };

    return (

      {items.map((item) => (
      // indexではなく、データ固有のIDをkeyに渡す

      ))}

    );
    };

    このコードのポイント

    • `memo` の利用: 親コンポーネントが再レンダリングされても、`data`が変わらない限り`Child`の差分計算自体をスキップさせます。
    • 一意な `key`: `id` を指定することで、Reactはツリー内の要素の「移動」や「挿入」を正確に特定でき、最小限のDOM操作(`insertBefore`など)だけで済みます。

    —

    最後に:職人としてのアドバイス

    Reactの Reconciliation は非常に賢いですが、万能ではありません。
    開発者が「何が変化し、何が変化していないのか」を設計段階で意識できているかどうかが、アプリのUXを左右します。

    「なんとなく動く」コードから、「なぜこれで効率的なのか」を説明できるコードへ。

    今回の話を意識して、コンポーネントを設計してみてください。Reactの裏側の挙動を味方につけた時、あなたの書くコードは一段階上のクオリティに到達しているはずです。

    何か疑問があれば、いつでも聞いてください。現場の泥臭い悩み、大歓迎ですよ。

    コメント

    タイトルとURLをコピーしました