Communitygithub.com

react-patterns

React 18/19のパターン集。フックの規律、サーバー/クライアントコンポーネントの境界、Suspense + エラーバウンダリ、フォームアクション、データフェッチ、状態管理の決定木、アクセシビリティ優先の構成を網羅。Reactコンポーネントの作成やレビュー時に使用。

react-patterns とは?

このスキルは、React 18および19における最新のベストプラクティスを一貫して適用するための包括的なガイドラインを提供します。主な内容は、副作用をレンダー外に追い出す純粋関数の原則、フックの使用ルール(トップレベルでのみ呼び出し、不要なメモ化を避ける)、状態管理の決定木(単一コンポーネントならuseState、複数コンポーネントで共有されるならリフトアップ、高頻度更新には外部ストア)です。また、Next.js App RouterなどのServer ComponentsとClient Componentsの適切な棲み分け、Suspenseとエラーバウンダリによる段階的なUI表示、React 19のuseActionStateを活用した型安全なフォーム実装、TanStack QueryやSWRを用いたデータフェッチの戦略もカバーします。開発者は、このスキルをReactコンポーネントの作成時やコードレビュー時にアクティブ化することで、パフォーマンス、アクセシビリティ、保守性に優れた実装を迅速に行えます。

対応✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/ECC/tree/main/skills/react-patterns

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

React Patterns

堅牢でアクセシブル、かつパフォーマンスの高いコンポーネントツリーを構築するための、慣用的な React 18/19 パターン。

有効化するタイミング

  • React の関数コンポーネント、カスタムフック、またはコンポーネントツリーを作成または修正する場合
  • JSX/TSX ファイルをレビューする場合
  • 状態の形状やコンポーネント構成を設計する場合
  • クラスコンポーネントや古い forwardRef/useEffect 主体のコードを移行する場合
  • ローカル状態、リフトされた状態、コンテキスト、外部ストアの選択肢を比較検討する場合
  • Server Components / Client Components(Next.js App Router、RSC)を扱う場合
  • React 19 のアクションや制御された入力を使ってフォームを実装する場合
  • TanStack Query / SWR / RSC を使用したデータフェッチを配線する場合

基本原則

1. レンダーは Props と State の純粋関数

// 良い: レンダー中に導出する
function Cart({ items }: { items: CartItem[] }) {
  const total = items.reduce((sum, i) => sum + i.price * i.qty, 0);
  return <span>{formatMoney(total)}</span>;
}

// 悪い: 導出状態を別途保存する
function Cart({ items }: { items: CartItem[] }) {
  const [total, setTotal] = useState(0);
  useEffect(() => {
    setTotal(items.reduce((sum, i) => sum + i.price * i.qty, 0));
  }, [items]);
  return <span>{formatMoney(total)}</span>;
}

useEffect 内の導出状態はレンダーサイクルを追加し、非同期の原因となり、データフローを不明瞭にします。

2. 副作用はレンダー外で

エフェクト、ミューテーション、ネットワーク呼び出し、サブスクリプションはイベントハンドラまたは useEffect 内に配置し、レンダー本体には決して書かないでください。

3. 継承より合成を

React にはコンポーネントの継承モデルはありません。children、レンダープロップ、コンポーネントプロップを使用して合成します。

フックの規律

完全なルールセットについては、rules/react/hooks.md を参照してください。ハイライト:

  • トップレベルでのみ使用し、条件付きで使用しない
  • すべてのサブスクリプション、インターバル、リスナーをクリーンアップする
  • 新しい状態が古い状態に依存する場合は、関数型アップデータ(setX(prev => prev + 1))を使用する
  • デフォルトの立場: メモ化しない。プロファイラまたは依存関係チェーンで重要であることが証明された場合にのみ useMemo/useCallback を追加する
  • 同じフックのシーケンスが 2 つ以上のコンポーネントに現れる場合にのみ、カスタムフックを抽出する

状態配置の決定木

1 つのコンポーネントのみで使用?
  → その中で useState

親 + いくつかの子孫で使用?
  → 最も近い共通祖先にリフト

異なるブランチで使用され、読み取り頻度が低い(テーマ、認証、ロケール)?
  → React Context

ツリー全体で共有される高頻度の更新?
  → 外部ストア(Zustand、Jotai、Redux Toolkit)

サーバーから派生?
  → サーバー状態ライブラリ(TanStack Query、SWR、RSC fetch)

ほとんどのページはコンテキストやグローバルストアを必要としません。重複したリフトが苦痛になるまで、抽象化は控えてください。

Server / Client Components(RSC)

// Server Component - デフォルト、非同期、自身の JS を送信しない
export default async function ProductPage({ params }: { params: { id: string } }) {
  const product = await db.product.findUnique({ where: { id: params.id } });
  if (!product) notFound();
  return <ProductView product={product} />;
}

// Client Component - "use client" でオプトイン
"use client";
export function AddToCartButton({ productId }: { productId: string }) {
  const [pending, startTransition] = useTransition();
  return (
    <button
      disabled={pending}
      onClick={() => startTransition(() => addToCart(productId))}
    >
      {pending ? "Adding..." : "Add to cart"}
    </button>
  );
}

境界:

  • Server -> Client: シリアライズ可能な props または children を渡す
  • Client -> Server: <form action={...}> を介して Server Actions を呼び出すか、イベントハンドラから命令的に呼び出す
  • Client Component ファイルから Server Component を import しないでください。代わりに children を介して構成してください

Suspense + Error Boundaries

<ErrorBoundary fallback={<ErrorView />}>
  <Suspense fallback={<UserSkeleton />}>
    <UserDetail id={id} />
  </Suspense>
</ErrorBoundary>
  • Suspense 境界はルートルートではなくデータの近くに配置し、コンテンツを段階的に明らかにします
  • Error Boundary は引き続きクラス API です。フックに適したラッパーには react-error-boundary を使用してください
  • 境界は、その子のレンダー、ライフサイクル、コンストラクター中にスローされたエラーをキャッチします。イベントハンドラや非同期コード内のエラーはキャッチしません

フォーム

React 19 フォームアクション(新しいコードに推奨)

"use client";
import { useActionState } from "react";

const initial = { error: null as string | null };

async function updateUserAction(_prev: typeof initial, formData: FormData) {
  "use server";
  const parsed = UserSchema.safeParse(Object.fromEntries(formData));
  if (!parsed.success) return { error: "Invalid input" };
  await db.user.update({ where: { id: parsed.data.id }, data: parsed.data });
  return { error: null };
}

export function UserForm() {
  const [state, formAction, pending] = useActionState(updateUserAction, initial);
  return (
    <form action={formAction}>
      <input name="name" required />
      <button type="submit" disabled={pending}>Save</button>
      {state.error && <p role="alert">{state.error}</p>}
    </form>
  );
}

制御された入力

値が他の UI を駆動する場合、キー入力ごとにフォーマットする場合、またはリアルタイム検証を実装する場合は、制御された入力を使用します。

複雑なフォーム

マルチステップフォーム、動的フィールド配列、またはフィールド間の検証には、ライブラリ(React Hook Form、TanStack Form)を使用します。些細な複雑さを超えたフォームの状態管理を独自に実装することは、メンテナンスの罠です。

データフェッチの決定マトリックス

ニーズツール
Next.js App Router でのリクエストごとのデータRSC await fetch()
クライアント側キャッシュ + ミューテーション + 無効化TanStack Query
軽量クライアントキャッシュ + 再検証SWR
リアルタイムサブスクリプションServer-Sent Events、WebSocket、またはライブラリのサブスクリプション API
1 回限りのファイアアンドフォーゲットイベントハンドラ内の fetch()

アプリケーションデータには useEffect + fetch を避けてください — 競合状態、キャッシュなし、リトライなし、Suspense 統合なし。

構成レシピ

children によるスロット

<Layout>
  <Header />
  <Main>{content}</Main>
</Layout>

名前付きスロット

<Page header={<Nav />} sidebar={<Filters />}>
  <Results />
</Page>

複合コンポーネント(Context を介した共有状態)

<Tabs defaultValue="profile">
  <Tabs.List>
    <Tabs.Trigger value="profile">Profile</Tabs.Trigger>
    <Tabs.Trigger value="settings">Settings</Tabs.Trigger>
  </Tabs.List>
  <Tabs.Panel value="profile"><Profile /></Tabs.Panel>
  <Tabs.Panel value="settings"><Settings /></Tabs.Panel>
</Tabs>

レンダープロップ / 関数を子として

親がレンダリング出力にパラメーターを渡す必要がある場合に便利です:

<DataLoader id={id}>
  {({ data, isLoading }) => isLoading ? <Spinner /> : <UserCard user={data} />}
</DataLoader>

最新の代替手段: 同じ形状を返すフック(useData(id))— 通常はよりクリーンです。

パフォーマンス

React.memo が実際に役立つ場合

以下の場合にのみ、コンポーネントを React.memo でラップします:

  1. 頻繁に再レンダリングされる
  2. プロップがレンダリング間で通常は同じである
  3. レンダリングが計測可能なほど高コストである

React.memo はすべてのレンダーで等価性チェックを追加します。ほとんどのレンダーでプロップが異なる場合、そのチェックは純粋なオーバーヘッドになります。

レンダリングカスケードの回避

  • 可能な限り、状態を上げるのではなく下げる
  • コンテキストを分割する: 関心事ごとに 1 つのコンテキスト。これにより、themeContext の変更が認証コンシューマーを再レンダリングしなくなります
  • 外部状態ライブラリには useSyncExternalStore を使用する — 安全な並行レンダリングに必須

リスト

  • 安定した key プロップを指定する(データベース ID、配列インデックスは不可)
  • 表示されるアイテム数が非自明な行で約 50 を超える場合は、@tanstack/react-virtual または react-window で長いリストを仮想化する

アクセシビリティファーストの構成

  • role 属性に手を伸ばす前に、常にセマンティック HTML(<button>、<a>、<nav>、<main>)をレンダリングする
  • すべてのインタラクティブ要素はキーボードで到達可能である必要があります
  • フォーム入力にはラベルが必要です — <label htmlFor>、またはアイコンで視覚的にラベル付けされている場合は aria-label
  • ルート変更時およびモーダルの開閉時にフォーカスを管理する
  • コンポーネントテストで axe を実行する(skills/react-testing を参照)
  • 相互リンク: skills/accessibility/SKILL.md では、WCAG 基準とパターンライブラリについて説明しています

ルーティング

このスキルはルーターに依存しません。上記のパターンは、React Router、TanStack Router、Next.js App Router、Remix Router で機能します。ルーター固有のパターン(ローダー、アクション、ネストされたレイアウト)は、ルーターのドキュメントに従います — これらは React コアの上に重ねられたフレームワークの関心事です。

範囲外(ポインターセクション)

  • Next.js 固有の事項: App Router データ読み込み、Route Handlers、Middleware、Parallel Routes — 別の関心事。Next.js ドキュメントを参照
  • React Native: プラットフォーム固有のパターンは、別の react-native-patterns スキルを正当化するほど異なります(まだ存在しません)
  • Remix: Loader/action の規則は RSC と重複しますが、Remix のドキュメントに従います

関連

  • ルール: rules/react/ — コーディングスタイル、フック、パターン、セキュリティ、テスト
  • スキル: react-performance(Vercel 由来のパフォーマンスルールセット)、frontend-patterns(フレームワーク横断的な UI 関心事)、アクセシビリティ、angular-developer(フレームワーク比較用)
  • エージェント: react-reviewer(コードレビュー用)、react-build-resolver(ビルド/バンドラーエラー用)
  • コマンド: /react-review、/react-build、/react-test

例

デバウンス検索のためのカスタムフック

function useDebounce<T>(value: T, delay = 300): T {
  const [debounced, setDebounced] = useState(value);
  useEffect(() => {
    const id = setTimeout(() => setDebounced(value), delay);
    return () => clearTimeout(id);
  }, [value, delay]);
  return debounced;
}

function SearchBox() {
  const [query, setQuery] = useState("");
  const debounced = useDebounce(query, 300);
  const { data } = useQuery({
    queryKey: ["search", debounced],
    queryFn: () => searchApi(debounced),
    enabled: debounced.length > 0,
  });
  return (
    <>
      <input value={query} onChange={(e) => setQuery(e.target.value)} />
      <Results items={data ?? []} />
    </>
  );
}

React 19 useOptimistic を使用した楽観的 UI

"use client";
import { useOptimistic } from "react";

export function MessageList({ messages }: { messages: Message[] }) {
  const [optimistic, addOptimistic] = useOptimistic(
    messages,
    (state, newMessage: Message) => [...state, newMessage],
  );

  async function send(formData: FormData) {
    const text = String(formData.get("text"));
    addOptimistic({ id: "pending", text, sender: "me" });
    await saveMessage(text);
  }

  return (
    <>
      <ul>{optimistic.map((m) => <li key={m.id}>{m.text}</li>)}</ul>
      <form action={send}>
        <input name="text" />
        <button type="submit">Send</button>
      </form>
    </>
  );
}

レンダリングカスケードを避けるためのコンテキスト分割

// 2 つのコンテキスト: 1 つはほとんど変更されず、もう 1 つは頻繁に変更される
const ThemeContext = createContext<Theme>("light");
const NotificationsContext = createContext<Notification[]>([]);

// ThemeContext のみを消費するコンポーネントは、通知が変更されても再レンダリングされない

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/content-engine

Create platform-native content systems for X, LinkedIn, TikTok, YouTube, newsletters, and repurposed multi-platform campaigns. Use when the user wants social posts, threads, scripts, content calendars, or one source asset adapted cleanly across platforms.

affaan-m/ECC

Multi-platform content distribution across X, LinkedIn, Threads, and Bluesky. Adapts content per platform using content-engine patterns. Never posts identical content cross-platform. Use when the user wants to distribute content across social platforms.

affaan-m/fal-ai-media

Unified media generation via fal.ai MCP — image, video, and audio. Covers text-to-image (Nano Banana), text/image-to-video (Seedance, Kling, Veo 3), text-to-speech (CSM-1B), and video-to-audio (ThinkSound). Use when the user wants to generate images, videos, or audio with AI.

affaan-m/manim-video

日本語翻訳:このファイルは manim-video 用の日本語翻訳が必要です

affaan-m/remotion-video-creation

Remotion のベストプラクティス - React で動画を作成する。3D、アニメーション、音声、字幕、チャート、トランジションなどをカバーするドメイン固有の29のルール。

affaan-m/video-editing

AI-assisted video editing workflows for cutting, structuring, and augmenting real footage. Covers the full pipeline from raw capture through FFmpeg, Remotion, ElevenLabs, fal.ai, and final polish in Descript or CapCut. Use when the user wants to edit video, cut footage, create vlogs, or build video content.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

agent-self-evaluation

Use after completing any non-trivial task. The agent self-rates its output on 5 axes — accuracy, completeness, clarity, actionability, conciseness — with concrete evidence per criterion. Produces a structured 1-5 scorecard with specific improvement suggestions.

agent-sort

Build an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.

ai-first-engineering

Engineering operating model for teams where AI agents generate a large share of implementation output. Use when setting team process, review gates, or ownership rules for a codebase largely written by agents.

ai-regression-testing

Regression testing strategies for AI-assisted development. Sandbox-mode API testing without database dependencies, automated bug-check workflows, and patterns to catch AI blind spots where the same model writes and reviews code. Use when adding regression coverage to AI-assisted code, or when the same model both wrote and reviewed a change.

android-clean-architecture

Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns. Use when structuring modules, layers, or data flow in an Android or KMP project.

angular-developer

Generates Angular code and provides architectural guidance. Trigger when creating projects, components, or services, or for best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling (component styles, Tailwind CSS), testing, or CLI tooling.

関連スキル