Agent Skills by ALSEL
Anthropic Claudeソフトウェア開発⭐ リポ 0品質スコア 50/100

react-patterns

React 19のServer Components、Server Actions、`useOptimistic`、`useActionState`、`useTransition`、並行機能、Suspenseバウンダリ、TypeScript統合に関する包括的なパターンを提供します。実行可能なコードパターンを生成し、公開エンドポイントのセキュリティ検証や、React Compilerまたは手動メモ化によるパフォーマンス最適化も行います。Next.js App RouterでReact 19アプリを構築する際、楽観的UIの実装、または並行レンダリングの最適化が必要な場面で積極的に活用してください。

description の原文を見る

Provides comprehensive React 19 patterns for Server Components, Server Actions, useOptimistic, useActionState, useTransition, concurrent features, Suspense boundaries, and TypeScript integration. Generates executable code patterns, validates security for public endpoints, and optimizes performance with React Compiler or manual memoization. Proactively use when building React 19 applications with Next.js App Router, implementing optimistic UI, or optimizing concurrent rendering.

SKILL.md 本文

React 19 開発パターン

概要

Next.js App Router、Server Actions、楽観的 UI、および並行機能に対応した React 19 パターン。クイックリファレンスで API の概要を、Examples でコピー&ペーストできるパターンを確認できます。

使用時期

  • React 19 アプリケーションを Next.js App Router で構築する
  • useOptimistic または useTransition で楽観的 UI を実装する
  • フォーム検証を備えた Server Actions を作成する
  • クラスコンポーネントからフックへの移行
  • React Compiler で並行レンダリングを最適化する
  • useReducer またはカスタムフックで複雑な状態を管理する
  • 非同期操作を Suspense boundaries でラップする

クイックリファレンス

パターンフック / API用途
ローカル状態useStateシンプルなコンポーネント状態
複雑な状態useReducerマルチアクション状態マシン
サイドエフェクトuseEffectサブスクリプション、データフェッチング
共有状態useContext / createContextクロスコンポーネントデータ
DOM アクセスuseRefフォーカス、測定、タイマー
パフォーマンスuseMemo / useCallback高コスト計算
非緊急更新useTransition大規模リストの検索/フィルター
高コスト UI の遅延useDeferredValue古い値を表示しながら更新
リソース読み込みuse() (React 19)レンダー内で Promise とコンテキスト
楽観的 UIuseOptimistic (React 19)ミューテーション時の即座フィードバック
フォーム状態useFormStatus (React 19)子コンポーネント内の保留状態
フォーム状態useActionState (React 19)Server アクションの結果
自動メモ化React Compiler手動 memo/callback を削除

手順

  1. コンポーネントタイプを識別: Server Component または Client Component が必要かを判定
  2. フックを選択: 状態管理とサイドエフェクト用の適切なフックを使用
  3. Props をタイプ: すべてのコンポーネント props に TypeScript インターフェースを定義
  4. 非同期処理を処理: データフェッチングコンポーネントを Suspense boundaries でラップ
  5. 最適化: React Compiler または手動メモ化を使用して高コストレンダリング
  6. エラーを処理: ErrorBoundary を追加してグレースフルなエラーハンドリング
  7. Server Actions を検証: Zod/スキーマ検証を定義し、テスト:
    • 無効な入力を送信 → 拒否を確認
    • 有効な入力を送信 → 成功を確認

Server Component とクライアント相互作用

// Server Component (デフォルト) — 非同期、データをフェッチ
async function ProductPage({ id }: { id: string }) {
  const product = await db.product.findUnique({ where: { id } });

  return (
    <div>
      <h1>{product.name}</h1>
      <AddToCartButton productId={product.id} />
    </div>
  );
}

// Client Component — インタラクティビティを処理
'use client';
function AddToCartButton({ productId }: { productId: string }) {
  const [isPending, startTransition] = useTransition();

  const handleAdd = () => {
    startTransition(async () => {
      await addToCart(productId);
    });
  };

  return (
    <button onClick={handleAdd} disabled={isPending}>
      {isPending ? 'Adding...' : 'Add to Cart'}
    </button>
  );
}

useOptimistic で即座フィードバック

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

function TodoList({ todos, addTodo }: { todos: Todo[]; addTodo: (t: Todo) => Promise<void> }) {
  const [optimisticTodos, addOptimisticTodo] = useOptimistic(
    todos,
    (state, newTodo: Todo) => [...state, { ...newTodo, pending: true }]
  );

  const handleSubmit = async (formData: FormData) => {
    const newTodo = { id: Date.now(), text: formData.get('text') as string };
    addOptimisticTodo(newTodo);  // 即座な UI 更新
    await addTodo(newTodo);      // 実際のバックエンド呼び出し
  };

  return (
    <form action={handleSubmit}>
      {optimisticTodos.map(todo => (
        <div key={todo.id} style={{ opacity: todo.pending ? 0.5 : 1 }}>
          {todo.text}
        </div>
      ))}
      <input type="text" name="text" />
      <button type="submit">Add</button>
    </form>
  );
}

フォーム付き Server Action

// app/actions.ts
'use server';
import { z } from 'zod';
import { revalidatePath } from 'next/cache';

const schema = z.object({
  title: z.string().min(5),
  content: z.string().min(10),
});

export async function createPost(prevState: any, formData: FormData) {
  const parsed = schema.safeParse({
    title: formData.get('title'),
    content: formData.get('content'),
  });

  if (!parsed.success) {
    return { errors: parsed.error.flatten().fieldErrors };
  }

  await db.post.create({ data: parsed.data });
  revalidatePath('/posts');
  return { success: true };
}

// app/blog/new/page.tsx
'use client';
import { useActionState } from 'react';
import { createPost } from '../actions';

export default function NewPostPage() {
  const [state, formAction, pending] = useActionState(createPost, {});

  return (
    <form action={formAction}>
      <input name="title" placeholder="Title" />
      {state.errors?.title && <span>{state.errors.title[0]}</span>}
      <textarea name="content" placeholder="Content" />
      <button type="submit" disabled={pending}>
        {pending ? 'Publishing...' : 'Publish'}
      </button>
    </form>
  );
}

カスタムフック

export function useOnlineStatus() {
  const [isOnline, setIsOnline] = useState(true);

  useEffect(() => {
    function handleOnline() { setIsOnline(true); }
    function handleOffline() { setIsOnline(false); }

    window.addEventListener('online', handleOnline);
    window.addEventListener('offline', handleOffline);

    return () => {
      window.removeEventListener('online', handleOnline);
      window.removeEventListener('offline', handleOffline);
    };
  }, []);

  return isOnline;
}

非緊急更新用 useTransition

function SearchableList({ items }: { items: Item[] }) {
  const [query, setQuery] = useState('');
  const [isPending, startTransition] = useTransition();
  const [filteredItems, setFilteredItems] = useState(items);

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setQuery(e.target.value);
    startTransition(() => {
      setFilteredItems(items.filter(i => i.name.toLowerCase().includes(e.target.value.toLowerCase())));
    });
  };

  return (
    <div>
      <input value={query} onChange={handleChange} />
      {isPending && <span>Filtering...</span>}
      <ul>{filteredItems.map(i => <li key={i.id}>{i.name}</li>)}</ul>
    </div>
  );
}

ベストプラクティス

Server vs Client の判定

  • Server Component から始める (ディレクティブは不要)
  • 'use client' を追加するのは: フック、ブラウザ API、イベントハンドラーの場合のみ

状態管理

  • 状態は最小限に — 派生値を effects ではなくレンダー時に計算
  • 複数の関連アクションを持つ状態には useReducer を使用
  • 状態を最も近い共通の祖先まで上げる

Effects

  • effects は外部システム同期のみに使用
  • 常に正しい依存配列を指定
  • サブスクリプションとタイマーのためのクリーンアップ関数を返す
  • 状態を直接変更しない — 常に新しい参照を作成

パフォーマンス

  • React Compiler を使用する場合: 手動の useMemouseCallbackmemo を避ける
  • React Compiler がない場合: 高コスト計算に useMemo を、安定したコールバックに useCallback を使用
  • 低優先度の状態更新に useTransition を使用
  • 安定した ID をリストキーとして使用し、配列インデックスは使用しない

React 19 固有

  • use(promise) コンポーネントを Suspense boundaries でラップ
  • フォーム-server action 統合に useActionState を使用
  • Server Action 入力を検証 — これらは公開エンドポイント
  • Server から Client Components にシリアライズ可能なデータを渡す

制約と警告

  • Server Components: フック、イベントハンドラー、またはブラウザ API を使用できない
  • use() フック: レンダー中にのみ呼び出し可能、コールバックまたは effects では不可
  • Server Actions: 'use server' ディレクティブを含める必須、常に入力を検証
  • 状態ミューテーション: 状態を直接変更しない — 常に新しい参照を作成
  • Effect 依存: useEffect 依存配列にすべての依存を含める
  • メモリリーク: useEffect return でサブスクリプションとイベントリスナーを常にクリーンアップ

参考資料

詳細なパターンについては以下のファイルを参照してください:

  • references/hooks-patterns.md — useState、useEffect、useRef、useReducer、カスタムフック、一般的な落とし穴
  • references/component-patterns.md — Props、合成、状態の上げ方、コンテキスト、複合コンポーネント、エラーバウンダリー
  • references/react19-features.md — use()、useOptimistic、useFormStatus、useActionState、Server Actions、Server Components、移行ガイド
  • references/performance-patterns.md — React Compiler セットアップ、useMemo、useCallback、useTransition、useDeferredValue、遅延ロード
  • references/typescript-patterns.md — 型付き Props、ジェネリックコンポーネント、イベントハンドラー、判別用ユニオン、コンテキスト型付け
  • references/learn.md — 基本から高度な React 19 までの段階的学習ガイド
  • references/reference.md — すべての React フックおよびコンポーネント API の完全 API リファレンス

ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ

詳細情報

作者
giuseppe-trisciuoglio
リポジトリ
giuseppe-trisciuoglio/developer-kit
ライセンス
MIT
最終更新
不明

Source: https://github.com/giuseppe-trisciuoglio/developer-kit / ライセンス: MIT

関連スキル

汎用ソフトウェア開発⭐ リポ 39,967

doubt-driven-development

重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。

by addyosmani
汎用ソフトウェア開発⭐ リポ 1,175

apprun-skills

TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。

by yysun
OpenAIソフトウェア開発⭐ リポ 797

desloppify

コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。

by Git-on-my-level
汎用ソフトウェア開発⭐ リポ 39,967

debugging-and-error-recovery

テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。

by addyosmani
汎用ソフトウェア開発⭐ リポ 39,967

test-driven-development

テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。

by addyosmani
汎用ソフトウェア開発⭐ リポ 39,967

incremental-implementation

変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。

by addyosmani
本サイトは GitHub 上で公開されているオープンソースの SKILL.md ファイルをクロール・インデックス化したものです。 各スキルの著作権は原作者に帰属します。掲載に問題がある場合は info@alsel.co.jp または /takedown フォームよりご連絡ください。
原作者: giuseppe-trisciuoglio · giuseppe-trisciuoglio/developer-kit · ライセンス: MIT