mcpField
R
react19-patterns

react19-patterns

github.com/qingqishi開発558 回インストール今日更新
リポジトリ

react19-patterns について

React Compilerを有効にしたReact 19プロジェクト向けのコーディングスキルです。Contextと`use()`のパターン、コンパイラーによる最適化、ViewTransitionとSuspenseの境界設定を扱います。

主な機能

  1. 01React 19のContextプロバイダー構文
  2. 02`useContext()`の代わりに`use()`を使用
  3. 03コンパイラーのメモ化を活用
  4. 04不要な手動最適化を回避
  5. 05ViewTransitionとSuspenseの調整

活用シーン

  1. 01React 19コンポーネントでのContext利用
  2. 02冗長な手動メモ化の削除
  3. 03Suspenseによるハイドレーション不一致の防止
  4. 04手動最適化前のパフォーマンス計測

インストール

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

$npx skills add https://github.com/qingqishi/shiqingqi.com --skill react19-patterns

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

詳細

React 19 のパターン

概要

このプロジェクトでは、React Compiler を有効にした React 19 を使用しています。これにより、特に Context や最適化に関する React コードの書き方が変わります。

React 19 の Context パターン

短縮構文を使用する

React 19 では、Context プロバイダーの短縮構文が導入されています。

✅ 正しい例(React 19):

<MyContext value={someValue}>
  <ChildComponents />
</MyContext>

❌ 誤った例(古いパターン):

<MyContext.Provider value={someValue}>
  <ChildComponents />
</MyContext.Provider>
useContext() の代わりに use() フックを使用する

React 19 では、コンテキストを使用するための use() フックが導入されています。

✅ 正しい例(React 19):

import { use } from "react";
import { MyContext } from "./MyContext";

function MyComponent() {
  const value = use(MyContext);
  return <div>{value}</div>;
}

❌ 誤った例(古いパターン):

import { useContext } from "react";
import { MyContext } from "./MyContext";

function MyComponent() {
  const value = useContext(MyContext);
  return <div>{value}</div>;
}

React Compiler が有効

手動でのメモ化は不要

React Compiler はコンポーネントを自動的に最適化し、メモ化を処理します。手動でメモ化するパターンは使用しないでください。

✅ 正しい例(React Compiler が処理):

function MyComponent({ items }) {
  // React Compiler automatically memoizes this computation
  const filteredItems = items.filter((item) => item.active);

  // React Compiler automatically stabilizes this function reference
  const handleClick = (id) => {
    console.log(id);
  };

  return (
    <div>
      {filteredItems.map((item) => (
        <button key={item.id} onClick={() => handleClick(item.id)}>
          {item.name}
        </button>
      ))}
    </div>
  );
}

❌ 誤った例(手動でのメモ化は不要):

import { useMemo, useCallback, memo } from "react";

function MyComponent({ items }) {
  // ❌ Don't use useMemo - React Compiler handles this
  const filteredItems = useMemo(
    () => items.filter((item) => item.active),
    [items],
  );

  // ❌ Don't use useCallback - React Compiler handles this
  const handleClick = useCallback((id) => {
    console.log(id);
  }, []);

  return <div>...</div>;
}

// ❌ Don't use memo() - React Compiler handles this
export default memo(MyComponent);

React 19 の ViewTransition と Suspense のパターン

ハイドレーションの問題

<ViewTransition> で Suspense 境界を含むコンテンツをラップすると、一部の子要素が Suspense 内にあり、ほかの子要素がそうでない場合に、ハイドレーションエラーが発生することがあります。

エラーメッセージ:

A tree hydrated but some attributes of the server rendered HTML didn't match the client properties.
This won't be patched up. This can happen if a SSR-ed Client Component used...
Specifically: style={{view-transition-name:"_T_0_"}}

根本原因:

  • ViewTransition は、トランジションが開始されたときにのみ view-transition-name スタイルを適用する「ジャストインタイム」方式を使用します
  • SSR のハイドレーション中に、Suspense を含まない子要素からコンテンツが表示されると、ViewTransition が有効になります
  • その結果、サーバーの HTML にはなかったスタイルが、ハイドレーション中にクライアント側で適用されます
  • React が不一致を検出し、ハイドレーションの警告を記録します
解決策:Suspense 境界を統一する

✅ 正しい例(すべてのコンテンツを Suspense 内に配置):

<ViewTransition>
  <Suspense fallback={<HeaderSkeleton />}>
    <Header />
  </Suspense>
  <Suspense fallback={null}>{children}</Suspense>
</ViewTransition>

❌ 誤った例(Suspense 内外が混在):

<ViewTransition>
  <Suspense fallback={<HeaderSkeleton />}>
    <Header />
  </Suspense>
  {children} {/* NOT in Suspense - causes hydration error! */}
</ViewTransition>

別の方法(ViewTransition の外側に Suspense を配置):

<Suspense fallback={<LoadingSkeleton />}>
  <ViewTransition>
    <Header />
    {children}
  </ViewTransition>
</Suspense>

注:この方法では、すべてのコンテンツが同じローディング状態になります。Header と子要素を個別に読み込む必要がある場合は、望ましくないことがあります。

この修正で解決する理由

すべての子要素を Suspense 境界でラップすると、次のようになります。

  • コンテンツの表示が React の Suspense 機構を通じて調整されます
  • ハイドレーション中に ViewTransition が早期に有効になることを防ぎます
  • サーバーとクライアントのレンダリングの一貫性が保たれます
  • ハイドレーションの不一致が発生しなくなります

主なルール

  1. Context の短縮構文:<Context.Provider value={...}> ではなく、常に <Context value={...}> を使用します
  2. use() フック:useContext(Context) ではなく、常に use(Context) を使用します
  3. useMemo は使用しない:React Compiler が負荷の高い計算を自動的にメモ化します
  4. useCallback は使用しない:React Compiler が関数の参照を自動的に安定させます
  5. memo() は使用しない:React Compiler がコンポーネントの再レンダリングを自動的に最適化します
  6. コンパイラーを信頼する:手動のパターンではなく、React Compiler に最適化を任せます
  7. ViewTransition と Suspense:ViewTransition を Suspense と併用する場合は、ハイドレーションエラーを防ぐため、すべての子要素を Suspense 境界内に配置します

手動での最適化が必要になる場合

まれに、手動での最適化が必要になることがあります。

  • 安定した参照を必要とする外部ライブラリとの連携
  • パフォーマンスのプロファイリングで、React Compiler が検出できない特定の問題が確認された場合

手動で最適化を追加する前に、必ずプロファイリングを行ってください。 React Compiler は非常に効果的です。

コメント