Back

React Compiler vs 手動メモ化

React Compiler vs 手動メモ化

長年にわたり、Reactのパフォーマンス最適化といえば一つのことを意味していました。コードベース全体に useMemouseCallbackReact.memo を散りばめ、依存配列が正しいことを祈ることです。React Compilerはその方程式を変えます。しかし、どの程度変えるのでしょうか?そして、モダンなReactアプリケーションにおいて手動メモ化はまだ役割を持っているのでしょうか?

ここでは、本当に知っておくべきことをお伝えします。

要点

  • React Compilerは、静的解析に基づいて React.memouseMemouseCallback と同等の処理を自動的に適用するビルド時ツールです。
  • コールバックprops、propsとしてのchildren、カスタムフックの戻り値など、一般的なパターンの処理に優れています。
  • サードパーティ製フックが返す不安定なオブジェクト、エフェクトの依存関係、プロファイリングで特定されたボトルネックに対しては、手動メモ化が依然として重要です。
  • 新しい考え方:デフォルトではクリーンなコンポーネントを書き、測定可能な理由がある場合にのみ意図的にメモ化する。

React Compilerの機能

React Compilerは、コンポーネント、そのprops、フックの戻り値を自動的にメモ化するビルド時ツールです。コンパイル時にコードを解析し、React.memouseMemouseCallback でラップするのと同等の最適化を、そうしたコードを一切書かずに適用します。

現在は安定版でプロダクションレディとなっており、Metaの本番環境で使用されています。Babel、Vite、Metro、Rsbuildでサポートされています。Next.js 15.3.1以降は、ビルドパフォーマンスを向上させるためにSWCから呼び出されるReact Compilerパスをサポートしています。

ここでのキーワードは「ビルド時」です。React Compilerは任意の値に対するランタイムキャッシュではありません。コード構造の静的解析に基づいて、コンポーネントの再レンダリング最適化に特化しています。

React Compilerが自動的にメモ化を処理する場面

コンパイラは、一般的なケースをきれいに処理します:

  • 単純なstate変更 — 変更されたstateに依存しない兄弟コンポーネントは再レンダリングされません。
  • コールバックを含むprops — propsとして渡されたインラインアロー関数は、ネストされていても適切にメモ化されます。
  • propsとしてのchildren — 悪名高い useMemo(() => <Child />, []) パターンが不要になります。
  • カスタムフック — 戻り値は実際の依存関係に基づいてメモ化されます。

3番目のケースは立ち止まって考える価値があります。多くの開発者は手動でこれを誤ります。コンパイラは自動的に正しく処理します。

Reactにおける手動メモ化が依然として重要な場面

複数のコードベースでの実環境テストは、より地に足のついた現実を語っています。コンパイラは独立した自己完結型のコンポーネントをうまく処理します。一方で、サードパーティライブラリがメモ化されていないオブジェクトを返す場合には苦戦します。

最も明確な例は、React QueryuseMutation が毎レンダリングで新しいオブジェクトを返すことです。onDelete コールバックが、分割代入された mutate 関数ではなく deleteCountryMutation 自体に依存している場合、コンパイラはそれを安定化できません。修正は知ってしまえば簡単です。mutate を直接分割代入するだけです。しかし、コンパイラはその判断を代わりに下すことはできません。

// コンパイラに優しい: 安定した参照
const { mutate: deleteCountry } = useMutation(...)

// コンパイラに優しくない: 毎レンダリングで新しいオブジェクト
const deleteCountryMutation = useMutation(...)
const onDelete = () => deleteCountryMutation.mutate(name)

その他、手動制御が依然として優位なケース:

  • エフェクトの依存関係useEffect が繰り返し発火するのを防ぐために、特にメモ化された値が必要な場合。
  • 動的リスト.map() 内でレンダリングされる行は、安定した key propを持つ名前付きコンポーネントに抽出することで恩恵を受けます。コンパイラは、インラインのレンダリング出力をまたぐよりも、コンポーネントでの最適化が得意です。
  • プロファイリング後のパフォーマンスチューニング — 特定のボトルネックを測定した場合、明示的な useMemo はコンパイラのヒューリスティックには真似できない精密な制御を提供します。

Reactのコーディング習慣をどう変えるべきか

メンタルモデルのシフトは明快です。防御的にメモ化するのをやめ、意図的にメモ化を始めるということです。

コンパイラ以前は、念のためにすべてをラップするのがデフォルトでした。これによりノイズが増え、メンテナンス負担が生じ、時には微妙なバグ(公式ドキュメントが今では強調している useCallback とインラインアロー関数の罠など)も生じていました。

React Compilerを有効にすると、新しいデフォルトはクリーンでシンプルなコンポーネントを書き、最適化はコンパイラに任せることです。useMemouseCallback に手を伸ばすのは、反射的にではなく、具体的で測定可能な理由がある場合に限ります。

今すぐ身につけるべき2つの実践的な習慣:

  1. リスト項目を名前付きコンポーネントに抽出する.map() 内のインラインJSXの代わりに <CountryRow /> を使う。
  2. サードパーティ製フックから安定した値を分割代入する — mutationオブジェクト全体ではなく mutate を直接使う。

実践的な結論

React Compilerは、Reactのパフォーマンス最適化における真の改善です。コードベースを散らかしていた防御的メモ化のほとんどを排除し、難しいchildren-as-propsパターンを多くの開発者が手動で行うよりもうまく処理します。

しかし、Reactの再レンダリングの仕組みを理解することの代替にはなりません。コンパイラから最大限の恩恵を得る開発者は、useMemo とReact Compilerのトレードオフを理解し、いつどちらに手を伸ばすべきかを知っている人たちでしょう。

結論

React Compilerは、Reactにおけるパフォーマンスの考え方にとって真の転機を示しています。あらゆる値や関数をメモ化ヘルパーでラップする反射的な習慣は、もはや正しいデフォルトではありません。よりシンプルなコードを書き、コンパイラに仕事をさせ、手動で最適化する前にプロファイリングしましょう。コンパイラが見ることのできないケース、特にサードパーティ製フックや測定されたボトルネック周辺のために、手動メモ化をツールキットに残しておきましょう。これが2026年以降も通用するアプローチです。

FAQ

はい。コンパイラは防御的メモ化のほとんどを処理しますが、サードパーティライブラリが返す不安定なオブジェクト、エフェクトの依存関係、測定されたパフォーマンスボトルネックなど、最適化できないケースのためにこれらのフックを理解する必要があります。再レンダリングの仕組みを理解することは、コンパイラがより効果的に最適化できるコードを書くのにも役立ちます。

いいえ。React Compilerは既存のuseMemo、useCallback、React.memoの呼び出しと共存するように設計されています。現在のメモ化を削除せずに段階的に導入できます。時間の経過とともに冗長な手動メモ化をクリーンアップできますが、プロジェクトでコンパイラを有効にする前に取り除く必要はありません。

useMutationが返すmutationオブジェクトは、毎レンダリングで新しい参照を持ちます。コンパイラはその内部メソッドが安定していることを判断できないため、オブジェクト全体に依存するコールバックは再作成されます。useMutationから安定したmutate関数を直接分割代入することでこの問題が解決され、コンパイラが依存するコールバックを正しくメモ化できるようになります。

Babel、Vite、Metro、Rsbuildをサポートしており、Next.js 15.3.1以降ではSWCを通じて有効になります。ほとんどのモダンなReactセットアップは、最小限の設定で導入できます。本番コードに統合する前に、サポートされているツールチェーンの最新リストとフレームワーク固有のセットアップ手順については、公式のReact Compilerドキュメントを確認してください。

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay