mcpField
R
react-advanced

react-advanced

github.com/bobmatnyc開発78194 回インストール15 週間前に更新
リポジトリ

react-advanced について

react-advancedは、Reactアプリを開発・最適化する開発者向けに、React 19のプラットフォーム機能とレンダリングアーキテクチャを解説するスキルです。React Compiler、並行レンダリング、Actions、コンポーネントパターン、性能、React Server Componentの境界を扱います。

主な機能

  1. 01React Compilerとメモ化の指針
  2. 02並行レンダリングのプリミティブ
  3. 03React 19のActionsとAPI
  4. 04高度なコンポーネント設計パターン
  5. 05レンダリング性能の最適化手法
  6. 06React Server Component境界の概念

活用シーン

  1. 01アプリへのReact Compiler導入
  2. 02負荷の高いレンダリング中の応答性維持
  3. 03React 19 Actionsを使ったフォーム構築
  4. 04コンテキストによる再レンダリングや大規模リストの性能問題の調査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/bobmatnyc/claude-mpm-skills --skill react-advanced

インストール後、Claude Code で/react-advancedを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

metadata.json
references/
component-patterns.md
concurrent-rendering.md
performance.md
react-compiler.md
react19-actions-and-apis.md
rsc-boundary.md

詳細

React Advanced:React 19 のプラットフォームとレンダリングアーキテクチャ

概要

React 19 世代のプラットフォーム機能とレンダリングアーキテクチャのリファレンスです。このスキルでは、現代の React アプリケーションの構築方法と最適化方法を大きく変える機能を扱います。React Compiler と、反射的な手動メモ化の終焉、並行レンダリングのプリミティブ、use() フック、Actions とフォームフック、React 19 の使いやすさを高める変更(通常のプロパティとしての ref、プロバイダーとしての <Context>、ネイティブのメタデータ)、高度なコンポーネントアーキテクチャのパターン、レンダリングパフォーマンスのエンジニアリング、そして React Server Component の境界に関する概念的な解説です。

このガイダンスでは、**React 19(2024 年 12 月)と React Compiler 1.0(2025 年 10 月に安定版)**を現行として扱います。React 19 以前のメモ化のアドバイス、つまり値を反射的に useMemo/useCallback/React.memo でラップする方法は、新しいコードではアンチパターンになりました。コンパイラーが自動的にメモ化します。信頼できるドキュメントは react.dev にあります。このスキルはそれを繰り返すのではなく、要点をまとめて応用します。

対象範囲マップ:このスキルで扱わない内容

このスキルは、React 19 のプラットフォームとレンダリングアーキテクチャに焦点を絞っています。それ以外については、担当するスキルを参照してください。

トピック担当するスキル
基本的なフックのチュートリアル(useState/useEffect/useRef/useMemo/useCallback/useContext)、JSX、props/state、リスト、制御された入力react-core
高度なカスタムフックの組み合わせレシピ — SWR を利用したデータフック、デバウンス検索、メモ化したプロバイダー値のパターン、判別共用体によるフックの状態react-hooks-composition
XState v5(setup()、アクター、ガード、並列状態)を使った明示的な有限状態機械のモデリングreact-state-machine
React Query によるサーバー状態のキャッシュ、クエリの無効化、楽観的更新tanstack-query
プロバイダーを使わないストアによるグローバルなクライアント状態zustand
Server Components、Server Actions(revalidateTag/revalidatePath)、App Router のデータ取得、キャッシュ、Turbopack のフレームワークへの組み込みNext.js skills(nextjs-core、nextjs-v16)
ドッキングレイアウト UI(ドラッグ&ドロップ可能なパネル、スプリッター)flexlayout-react

このスキルでは、並行レンダリング、React の機能としての RSC 境界、React のプリミティブとしての Actions など、React レベルの概念を説明します。これらの概念をフレームワーク固有の方法で組み込む内容は、Next.js のスキルが担当します。

このスキルを使う場面

次のような場合に、このスキルを参照してください。

  • React Compiler を導入し、古いメモ化の習慣を見直す
  • 並行機能(useTransition、useDeferredValue、データ取得のための Suspense)を使い、UI の応答性を保つ
  • React 19 の Actions、フォーム、または use() フックを使って開発する
  • コンテキストの過剰な再レンダリング、大規模なリスト、コード分割など、レンダリングパフォーマンスを最適化する
  • 複合コンポーネント、コンテキストセレクター、エラーバウンダリー、ポータルを設計する
  • React レベルで RSC/'use client' 境界について考える

React Compiler — 手動メモ化の終わり

React Compiler は 2025-10-07 に 1.0 の安定版に到達しました。コンポーネントとフックをきめ細かく自動メモ化するビルド時ツールで、手書きの useMemo では表現できない 条件付き メモ化にも対応しています。React 17、18、19 で動作し、19 で最も高い性能を発揮します。

React 17/18 からの変更点: 値を useMemo/useCallback で、コンポーネントを React.memo でラップするという長年の推奨事項は、新しいコードでは不要になりました。メモ化はコンパイラーが処理します。反射的に手動メモ化を散りばめると、コードが冗長になり、かえってマイナスになることがあります。

// BEFORE (pre-compiler reflex): hand-memoize everything
const sorted = useMemo(() => items.slice().sort(compare), [items]);
const onPick = useCallback((id: string) => onSelect(id), [onSelect]);
const Row = React.memo(function Row({ item }: { item: Item }) { /* ... */ });
// AFTER (compiler enabled): write plain code; the compiler memoizes
const sorted = items.slice().sort(compare);
const onPick = (id: string) => onSelect(id);
function Row({ item }: { item: Item }) { /* ... */ }

手動メモ化が依然として必要な場合(回避策):

  • 計算値が エフェクトの依存配列 に渡され、パフォーマンスだけでなく正しさのために安定した参照を維持する必要がある場合。
  • コンパイラーが静的に解析できないコード。誤ったコンパイルをするのではなく、そのようなコンポーネントを安全にスキップするため、手動メモ化は局所的な最適化として引き続き有効です。

既存のコード: コンパイラーは意図的に手動メモ化を 保持します。preserve-manual-memoization リントルールは、重要な役割を果たしているメモ化に警告を出します。コンパイラーを有効にした後、useMemo/useCallback を無条件に削除しないでください。

導入手順: eslint-plugin-react-hooks v6+(以前の eslint-plugin-react-compiler を統合)をインストールする → 報告された React のルール違反を修正する → ビルドでコンパイラーを有効にする(Babel/Vite/Metro/Rsbuild)。React DevTools では、コンパイラーにより最適化されたコンポーネントに「Memo ✨」バッジが表示されます。

導入ガイド、バンドラー別のセットアップ、導入前後の分析については、react-compiler.md を参照してください。

Concurrent Rendering

コンカレント機能を使うと、React はレンダリングを中断して優先順位を付けられるため、緊急性の高い更新(入力など)の応答性を保ちながら、負荷の高い更新(大きなリストのフィルタリングなど)を後回しにできます。

  • useTransition は状態更新を緊急性の低いものとしてマークし、isPending を公開します。トランジションのレンダリング中も、React は古い UI を操作可能な状態に保ちます。
  • React 19 の非同期トランジション: startTransition は非同期関数を受け取ります。注意点として、await の 後に 発行された状態更新は、再度 startTransition でラップしない限り、トランジションの対象外になります。
  • useDeferredValue は遅延した値のコピーを生成します。処理を中断でき、デバイスに応じて動作します。負荷の高い派生レンダリングでは、固定の setTimeout によるデバウンスよりもこちらを優先してください。React 19 では initialValue が追加されています。
  • データ用の Suspense は、スローされたプロミス(または use() で読み取ったプロミス)によってサスペンドし、最も近い <Suspense fallback> を表示します。key が変わると境界がリセットされます。
function ProductSearch({ allProducts }: { allProducts: Product[] }) {
  const [query, setQuery] = useState('');
  const deferredQuery = useDeferredValue(query); // lags behind input under load

  // Filtering reads the deferred value, so typing stays responsive.
  const results = allProducts.filter((p) => p.name.includes(deferredQuery));

  return (
    <>
      <input value={query} onChange={(e) => setQuery(e.target.value)} />
      <ResultsList results={results} stale={query !== deferredQuery} />
    </>
  );
}

React レベルのストリーミング SSR(renderToPipeableStream、シェルの設計、19.2 での Suspense 表示のバッチ処理)については concurrent-rendering.md で解説しています。フレームワーク固有のストリーミングについては、Next.js のスキルを参照してください。

React 19 のプラットフォームフックと API

use() フック

use() はプロミスまたはコンテキスト値を読み取り、条件付きで(早期リターンの後でも)呼び出すことができます。これは Hooks のルールに対する意図的な例外です。try/catch の中には置けません。拒否されたプロミスは、代わりに Error Boundary を通じて処理してください。レンダー中に作成したプロミスはレンダーのたびに再作成されるため、プロミスはツリーの上位(またはサーバー上)で作成して渡すことを推奨します。

Actions

Actions は、特定のフレームワークに依存しない、React レベルの非同期ミューテーション用プリミティブです。

  • useActionState(canary 版の useFormState から改名)はアクションを実行し、保留中およびエラーの状態を追跡しながら、前回の結果を次の処理に渡します。
  • useOptimistic はアクションの実行中に楽観的な値を表示し、完了時に自動で元に戻します。
  • useFormStatus は、props のバケツリレーなしで、子コンポーネントから親の <form> の保留中状態を読み取ります。
  • <form action={fn}> は関数を送信処理に直接つなぎ、成功時に自動でフォームをリセットします。
function NameForm({ save }: { save: (name: string) => Promise<string> }) {
  const [error, submit, isPending] = useActionState(
    async (_prev: string | null, formData: FormData) => {
      const result = await save(formData.get('name') as string);
      return result.startsWith('error') ? result : null;
    },
    null,
  );

  return (
    <form action={submit}>
      <input name="name" disabled={isPending} />
      {error && <p role="alert">{error}</p>}
    </form>
  );
}
人間工学的な変更
  • ref は通常の props です。 forwardRef は非推奨です(codemod が既存の使用箇所を移行します)。関数コンポーネントは、ほかの props と同様に ref を受け取ります。
  • <Context value> は、レガシーとなった <Context.Provider> に代わるものです。
  • ネイティブのドキュメントメタデータ: <title>、<meta>、<link> は自動的に <head> に移動され、react-helmet に代わるものです。リソースヒントには preload/preinit/preconnect を使用します。

完全な例と、17/18 からの移行に関する注意事項:react19-actions-and-apis.md。

高度なコンポーネントパターン

  • 複合コンポーネントはコンテキストを通じて暗黙の状態を共有するため、親コンポーネントとサブコンポーネントは props のバケツリレーなしで連携できます(<Tabs>/<Tabs.Tab>)。
  • コンテキストの最適化: ネイティブコンテキストにはセレクターがありません。プロバイダーの値が変わると、すべてのコンシューマーが再レンダーされます。React.memo ではコンテキストによる再レンダーを防げません。また、use(Context) を使うと条件付きで読み取れるようになりますが、選択的な購読はできません。コンパイラーでも、大きなコンテキストによる過剰な再レンダーは解決できません。ネイティブな解決策は、プロバイダーの値をメモ化し、変更頻度に応じてコンテキストを分割することです。ユーザーランドの use-context-selector を使うと、スライス単位で購読できます(ただし、tearing やレガシーに関する注意点があります)。
  • レンダープロップとカスタムフック: ロジックの再利用にはフックが適しています。レンダープロップは、「何をレンダーするか」を扱うヘッドレスコンポーネントで引き続き役立ちます。
  • エラーバウンダリーは、引き続きクラスベースです。react-error-boundary は、ネイティブのバウンダリーでは捕捉できない非同期エラーやイベントハンドラーのエラーに対応するフック(useErrorBoundary)を提供します。React 19 では捕捉されたエラーが一度だけログに記録され、onCaughtError/onUncaughtError が追加されました。
  • ポータル(createPortal)が変更するのは DOM 上の配置だけです。コンテキストとエラーは DOM ツリーではなく、引き続き React ツリーを通じて伝播します。

選択ガイドと完全な例:component-patterns.md。

パフォーマンスアーキテクチャ

  • 仮想化では、表示中の行だけをレンダーします。最新のヘッドレスな選択肢は、TypeScript との相性が最も優れた @tanstack/react-virtual です。react-window は成熟していますが、開発が停滞しています。react-virtuoso は必要な機能が一式そろっています。仮想化の導入後は、アイテムごとのレンダラーのコストがボトルネックになるため、行の処理は軽く保ってください。
  • コード分割には、まずルート単位で React.lazy と Suspense を使います。小さなコンポーネントを多数の 10KB 未満のチャンクに分割しすぎると、メリットがないままリクエストのオーバーヘッドが増えるため、避けてください。
  • プロファイリングには、本番ビルドに対して React DevTools Profiler を使い、実際に何が、なぜ再レンダーされたかを確認します。Why-Did-You-Render は、回避可能な再レンダーの追跡に役立ちます。

ライブラリの比較、コード分割の戦略、アンチパターン → 検出 → 修正の完全な表:performance.md。

RSC/'use client' 境界(概念)

React Server Components は事前にレンダーされ、状態を保持したりエフェクトを実行したりできません。また、シリアライズ可能な出力を生成します。境界はレンダーツリーではなく、モジュール依存関係グラフ上で定義されます(モジュールの先頭に記述する 'use client' ディレクティブ)。Client Component に渡す props はシリアライズ可能でなければなりません。また、Client Component は children として渡された Server Component を引き続きレンダーできます。'use server' ディレクティブは Server Functions を示します。その引数は信頼できないものとして扱い、検証と認可を行う必要があります。

明示的に対象外: キャッシュ、ルートローダー、App Router のデータフェッチは Next.js のスキルの範囲です。RSC のバンドラー API は 19.x 内でもセマンティックバージョニングに従って安定していないため、React のバージョンを固定してください。概念モデルとフレームワークへの引き継ぎ:rsc-boundary.md。

避けるべきアンチパターン

❌ やってはいけない:コンパイラーを有効にした状態で、あらゆるものを手動でメモ化する
// BAD: redundant manual memo once the compiler is on; adds noise and cost
const value = useMemo(() => ({ a, b }), [a, b]);
const onClick = useCallback(() => doThing(a), [a]);
// GOOD: write plain code; let the compiler memoize
const value = { a, b };
const onClick = () => doThing(a);
❌ やってはいけない:コンパイラーを有効にした後、手動のメモ化を無条件に削除する
// BAD: removing memo that stabilized an effect dependency changes behavior
const config = { endpoint, token }; // recreated each render → effect re-fires
useEffect(() => subscribe(config), [config]);
// GOOD: keep the deliberate escape hatch the preserve-manual-memoization lint protects
const config = useMemo(() => ({ endpoint, token }), [endpoint, token]);
useEffect(() => subscribe(config), [config]);
❌ やってはいけない:更新頻度の高い状態を、1 つの大きなコンテキストに入れる
// BAD: every consumer re-renders when any field changes; memo cannot block it
const AppContext = createContext<{ theme: Theme; cursor: Point } | null>(null);
// GOOD: split by change frequency so fast-changing state is isolated
const ThemeContext = createContext<Theme | null>(null);   // changes rarely
const CursorContext = createContext<Point | null>(null);  // changes often
❌ やってはいけない:非同期トランジション内で await の後に状態を更新する
// BAD: the post-await update escapes the transition; isPending ends early
startTransition(async () => {
  const data = await load();
  setData(data); // not part of the transition
});
// GOOD: re-wrap the post-await update
startTransition(async () => {
  const data = await load();
  startTransition(() => setData(data));
});
❌ 避けること:新しい React 19 のコードで forwardRef / <Context.Provider> / react-helmet> を使い続ける
// BAD: superseded idioms in new code
const Input = forwardRef<HTMLInputElement, Props>((props, ref) => <input ref={ref} {...props} />);
<ThemeContext.Provider value={theme}>{children}</ThemeContext.Provider>;
// GOOD: ref as a plain prop, <Context> as provider, native metadata
function Input({ ref, ...props }: Props & { ref?: React.Ref<HTMLInputElement> }) {
  return <input ref={ref} {...props} />;
}
<ThemeContext value={theme}>{children}</ThemeContext>;

& { ref?: ... } の交差型が必要なのは、ref を公開する必要があるカスタムインターフェースである Props の場合だけです。組み込み要素をラップする場合、React.ComponentProps<'input'> から Props を導出すれば、型が正しく設定された ref がすでに含まれるため、交差型は冗長です。

関連スキルを使うタイミング

  • react-core:基礎 — コンポーネント、JSX、props/state、基本的なフック、リスト、制御された入力。
  • react-hooks-composition:カスタムフックの合成レシピ — SWR データフック、デバウンス検索、メモ化されたプロバイダー、非同期状態フック。
  • react-state-machine:複雑なフローで、あり得ない状態を表現できないようにするための、明示的な XState v5 有限状態マシン。
  • tanstack-query / zustand:それぞれ、サーバー状態のキャッシュとグローバルなクライアント状態。
  • Next.js skills:Server Components、Server Actions、ルーティング、キャッシュのフレームワーク連携。

ベストプラクティスのまとめ

  1. まずコンパイラーを導入する:eslint-plugin-react-hooks v6 以降を有効にして Rules of React の問題を修正し、その後 React Compiler を有効にします。
  2. 反射的なメモ化をやめる:useMemo / useCallback / React.memo は、意図的な回避策(エフェクト依存関係の安定性、または解析できないコード)が必要な場合にのみ使います。
  3. 並行性を活用して応答性を保つ:負荷の高いレンダリングには、手動のデバウンスより useTransition / useDeferredValue を優先します。await 後の更新は再度ラップします。
  4. ミューテーションには Actions を使う:useActionState + useOptimistic + useFormStatus で、React レベルの保留中、エラー、楽観的状態に対応できます。
  5. use() を正しく使う:条件付きで呼び出し、決して try/catch 内では呼び出さず、ツリーの上位でプロミスを作成します。
  6. React 19 の使いやすさを取り入れる:ref をプロパティとして使い、<Context value> とネイティブのメタデータを利用して、forwardRef と react-helmet を使わないようにします。
  7. コンテキストによる過剰な再レンダリングは構造的に解消する:値をメモ化し、コンテキストを分割します。コンパイラーでは解決できません。
  8. リストとバンドルのパフォーマンスを最適化する:大きなリストを仮想化し、ルートごとにコード分割して、本番ビルドでプロファイリングします。
  9. RSC の境界を守る:境界はモジュールグラフに基づきます。境界を越える props はシリアライズ可能にし、サーバー関数の入力を検証して、React のバージョンを固定します。

ナビゲーション

  • React Compiler:バンドラーごとの導入、ESLint / Rules of React、コンパイラーがスキップするもの、preserve-manual-memoization、導入前後の例。
  • 並行レンダリング:useTransition(同期/非同期 + await 後の注意点)、useDeferredValue、データ用 Suspense、ストリーミング SSR シェル、表示のバッチ処理、境界の key によるリセット。
  • React 19 の Actions と API:use()、useActionState、useOptimistic、useFormStatus、<form action>、ref-as-prop、useImperativeHandle、<Context value>、メタデータ/プリロード、および移行に関する注記。
  • コンポーネントパターン:複合コンポーネント、コンテキストセレクター/分割 + use-context-selector、レンダープロパティとフックの比較、エラーバウンダリー、ポータル。
  • パフォーマンス:仮想化ライブラリーの比較、コード分割の戦略、Profiler のワークフロー、アンチパターン → 検出 → 修正の一覧。
  • RSC の境界:'use client' / 'use server' の概念モデル、シリアライズのルール、サーバー関数のセキュリティ、Next.js への引き継ぎ、バージョンの固定。

参考資料

コメント