Communitygithub.com

react-patterns

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

react-patterns とは?

このスキルは、React 18/19の最新パターンに基づき、堅牢でアクセシブル、かつパフォーマンスの高いコンポーネントツリーを構築するための包括的なガイドです。フックの使用ルール(トップレベルでの宣言、依存関係の管理、メモ化の適切な使用)、サーバーコンポーネントとクライアントコンポーネントの境界設計、Suspenseとエラーバウンダリーによる段階的なコンテンツ表示、React 19のフォームアクションやuseOptimisticを用いた楽観的UIといった最新機能の実装方法を網羅しています。また、状態管理においては、useState、リフトアップ、React Context、外部ストア(Zustand、Jotai、Redux Toolkit)の選択基準を決定木で示し、データフェッチではTanStack QueryやSWRなどのライブラリの使い分けをマトリクスで整理しています。コンポーネント設計では、childrenスロット、名前付きスロット、複合コンポーネント、レンダープロップといったコンポジションパターンを紹介し、パフォーマンス改善のためにReact.memoの適切な使用条件やレンダーカスケードの防止方法、仮想リストの導入基準についても解説しています。アクセシビリティにも重点を置き、セマンティックHTMLの優先、キーボード操作の保証、フォーカス管理、テストでのaxe実行を推奨しています。このスキルはルーターに依存せず、React Router、TanStack Router、Next.js App Router、Remix Routerのいずれでも動作しますが、Next.jsやReact Nativeの固有パターンはスコープ外としています。開発者はこのガイドに従うことで、保守性が高く、チーム全体で一貫したコードベースを構築できます。

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

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

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

ドキュメント

React Patterns

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

アクティベーションのタイミング

  • React関数コンポーネント、カスタムフック、コンポーネントツリーを作成・修正するとき
  • JSX/TSXファイルをレビューするとき
  • 状態の構造やコンポーネント構成を設計するとき
  • クラスコンポーネントやforwardRef/useEffectが多い古いコードを移行するとき
  • ローカル状態、リフトアップ状態、コンテクスト、外部ストアの選択を検討するとき
  • サーバーコンポーネント / クライアントコンポーネント(Next.js App Router、RSC)を扱うとき
  • React 19のアクションまたは制御された入力でフォームを実装するとき
  • TanStack Query / SWR / RSC でデータフェッチを組み込むとき

基本原則

1. レンダーはプロパティと状態の純粋関数

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

// Bad: 導出状態を個別に保持
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)

ほとんどのページでContextやグローバルストアは必要ありません。リフトアップが煩わしくなるまで抽象化は控えてください。

サーバー/クライアントコンポーネント (RSC)

// Server Component - デフォルト、非同期、JSをクライアントに送らない
import { db } from '@/lib/db';
import { notFound } from 'next/navigation';
import { ProductView } from './ProductView';

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";
import { useTransition } from 'react';

export function AddToCartButton({ productId }: { productId: string }) {
  const [pending, startTransition] = useTransition();
  return (
    <button
      disabled={pending}
      onClick={() => startTransition(() => addToCart(productId))}
    >
      {pending ? "追加中..." : "カートに追加"}
    </button>
  );
}

境界:

  • Server -> Client: シリアライズ可能なプロップスまたは children を渡す
  • Client -> Server: <form action={...}> またはイベントハンドラから Server Action を実行
  • Client コンポーネントファイルから Server コンポーネントを import してはいけません — 代わりに children を使ってコンポジションします

Suspense + Error Boundaries

import { ErrorBoundary } from 'react-error-boundary';
import { Suspense } from 'react';

<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: "入力が無効です" };
  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}>保存</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、WebSockets、またはライブラリのサブスクリプションAPI
一度限りのfire-and-forgetイベントハンドラ内の 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">プロフィール</Tabs.Trigger>
    <Tabs.Trigger value="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 はすべてのレンダーで等価性チェックを追加します。ほとんどのレンダーでプロップスが異なる場合、そのチェックは純粋なオーバーヘッドです。

レンダーカスケードの防止

  • 状態は上方ではなく下方にリフトする
  • Context を分割する: 関心ごとに1つのContext。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、並行ルート — 別の関心事です。Next.jsのドキュメントを参照
  • React Native: プラットフォーム固有のパターンは大きく異なるため、別の react-native-patterns スキルが必要(現時点では存在しません)
  • Remix: Loader/actionの規則はRSCと重複しますが、Remixのドキュメントに従ってください

関連情報

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

例

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

import { useState, useEffect } from 'react';
import { useQuery } from '@tanstack/react-query';

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: "私" });
    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">送信</button>
      </form>
    </>
  );
}

レンダーカスケードを防ぐためのContext分割

import { createContext, useContext } from 'react';

// 2つのContext: 1つは滅多に変更されず、もう1つは頻繁に変更される
const ThemeContext = createContext<string>("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/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

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.

関連スキル