投稿日
Reactコンポーネントの設計指針:AI活用プロンプトの整備
もくじ
- はじめに
- 目次
- 1. 設計フロー概要
- フェーズ概要
- 2. コンポーネント分類
- ディレクトリ構造
- 3. 分類判定フロー
- 判定基準
- 4. カテゴリ別設計指針
- 4.1 UI Components
- 4.2 Form Components
- 4.3 Layout Components
- 4.4 Shared Components
- 4.5 Feature Components
- 4.6 Route Components
- 5. Server/Client Component判定
- 判定基準
- 境界設計のベストプラクティス
- 6. 状態管理戦略
- 7. View層とFoundation層の関係
- 8. コンポーネントの分離設計:AIへの依頼プロンプト
- 9. AIの応答サンプル
- まとめ
- Appendix:前提技術スタック
はじめに
本ドキュメントは、画面仕様書からReactコンポーネントを設計・実装するまでのフローを定義します。
6カテゴリのコンポーネント分類に基づき、一貫した設計判断を行うための指針を提供します。
最後に、これらの分類をAIに依頼するプロンプトをまとめます。
注記
本ガイドラインは「Next.js App Router + React Server Components」を前提とした設計体系であり、Pages Router や CSR 前提構成では同一の効果を保証しません。
目次
- 設計フロー概要
- コンポーネント分類
- 分類判定フロー
- カテゴリ別設計指針
- Server/Client Component判定
- 状態管理戦略
- View層とFoundation層の関係
- コンポーネントの分離設計:AIへの依頼プロンプト
- AIの応答サンプル
Appendix:前提技術スタック
1. 設計フロー概要
コンポーネント設計は3つのフェーズで進行します。
フェーズ概要
| Phase | 目的 | 主な成果物 |
|---|---|---|
| Phase 1: 構造設計 | コンポーネントの洗い出しと分類 | コンポーネント一覧、分類表 |
| Phase 2: インターフェース設計 | Props/State/イベントの定義 | 型定義ファイル、API設計書 |
| Phase 3: 品質担保 | バリデーション設計とテスト | Storybook、テストコード |
2. コンポーネント分類
本設計指針では、責務に基づく6カテゴリでコンポーネントを分類します。
| カテゴリ | 配置先 | 責務 | 基本境界 | 例 |
|---|---|---|---|---|
| UI Components | components/ui/ |
shadcn/ui準拠、ビジネスロジックなし | Client | Button, Input, Dialog |
| Form Components | components/forms/ |
フォーム専用、バリデーション連携 | Client | FormField, DatePicker |
| Layout Components | components/layouts/ |
レイアウト・構造のみ | Server | Header, Sidebar |
| Shared Components | components/shared/ |
アプリ内再利用、軽いロジック | 混在 | UserAvatar, SearchBar |
| Feature Components | features/{name}/components/ |
機能固有、ビジネスロジック含む | 混在 | UserProfile, OrderForm |
| Route Components | app/ |
ルーティング対応 | Server | page.tsx, layout.tsx |
ディレクトリ構造
src/
├── app/ # Route Components
│ ├── (auth)/
│ │ ├── login/page.tsx
│ │ └── layout.tsx
│ ├── dashboard/
│ │ ├── page.tsx
│ │ ├── loading.tsx
│ │ └── error.tsx
│ └── layout.tsx
│
├── components/
│ ├── ui/ # UI Components (shadcn/ui)
│ │ ├── button.tsx
│ │ ├── input.tsx
│ │ └── dialog.tsx
│ ├── forms/ # Form Components
│ │ ├── form-field.tsx
│ │ └── date-picker.tsx
│ ├── layouts/ # Layout Components
│ │ ├── header.tsx
│ │ └── sidebar.tsx
│ └── shared/ # Shared Components
│ ├── user-avatar.tsx
│ └── search-bar.tsx
│
└── features/ # Feature Components
└── users/
├── components/
│ └── user-profile.tsx
├── hooks/
│ └── use-user.ts
└── actions/
└── update-user.ts
3. 分類判定フロー
新規コンポーネントを作成する際は、以下のフローに従って分類を決定します。
判定基準
| 判定ポイント | Yes の場合 | 具体例 |
|---|---|---|
| ルーティング対応か? | Route Components | page.tsx, layout.tsx, error.tsx |
| shadcn/uiに存在するか? | UI Components | Button, Dialog, Tooltip など |
| フォーム入力専用か? | Form Components | バリデーション付きInput, DatePicker |
| レイアウト・構造のみか? | Layout Components | Header, Footer, Sidebar |
| ビジネスロジックを含むか? | Feature Components | API呼び出し、業務処理を含むコンポーネント |
| アプリ全体で再利用するか? | Shared Components | UserAvatar, LoadingSpinner |
4. カテゴリ別設計指針
各カテゴリの設計フローと注意点を示します。
4.1 UI Components
責務: 汎用的なUI部品。ビジネスロジックを持たず、見た目と基本的なインタラクションのみを担当します。
設計ポイント:
- shadcn/uiのコンポーネントを最優先で使用します
- 拡張が必要な場合はCVA(class-variance-authority)でvariants追加します
forwardRefでref転送に対応します- aria属性を適切に設定してください
// components/ui/button.tsx の拡張例
const buttonVariants = cva(
'inline-flex items-center justify-center rounded-md text-sm font-medium',
{
variants: {
variant: {
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
destructive: 'bg-destructive text-destructive-foreground',
// カスタムvariant追加
success: 'bg-green-600 text-white hover:bg-green-700',
},
size: {
default: 'h-9 px-4 py-2',
sm: 'h-8 px-3 text-xs',
lg: 'h-10 px-8',
},
},
}
)
4.2 Form Components
責務: フォーム入力に特化したコンポーネント。バリデーションとReact Hook Formとの連携を担当します。
設計ポイント:
- Zodでスキーマを定義してください
- React Hook Formの
Controllerまたはregisterと連携してください - エラーメッセージの表示ロジックを含めてください
- アクセシビリティ(
aria-invalid,aria-describedby)に対応してください
// components/forms/form-field.tsx の例
interface FormFieldProps {
name: string
label: string
error?: string
children: React.ReactNode
}
export function FormField({ name, label, error, children }: FormFieldProps) {
const id = `field-${name}`
const errorId = `${id}-error`
return (
<div className="space-y-2">
<label htmlFor={id} className="text-sm font-medium">
{label}
</label>
{children}
{error && (
<p id={errorId} className="text-sm text-destructive">
{error}
</p>
)}
</div>
)
}
4.3 Layout Components
責務: ページのレイアウト構造を定義します。ビジネスロジックを持たず、配置のみを担当します。
設計ポイント:
- 基本的にServer Componentとして実装します
childrenを活用してClient Componentを受け入れます- レスポンシブデザインに対応してください
- 適切な位置にSuspense境界を配置してください
// components/layouts/sidebar.tsx の例
interface SidebarProps {
children: React.ReactNode
}
export function Sidebar({ children }: SidebarProps) {
return (
<aside className="w-64 border-r bg-muted/40 p-4">
<nav className="space-y-2">
{children}
</nav>
</aside>
)
}
4.4 Shared Components
責務: アプリ全体で再利用される共通コンポーネントです。軽いロジックは含めますが、特定機能に依存しません。
設計ポイント:
- 特定のfeatureに依存しないようにしてください
- Propsで必要なデータを受け取る設計にしてください
- Server/Client境界は用途に応じて判断してください
// components/shared/user-avatar.tsx の例
interface UserAvatarProps {
name: string
imageUrl?: string
size?: 'sm' | 'md' | 'lg'
}
export function UserAvatar({ name, imageUrl, size = 'md' }: UserAvatarProps) {
const sizeClasses = {
sm: 'h-8 w-8',
md: 'h-10 w-10',
lg: 'h-12 w-12',
}
return (
<div className={cn('rounded-full bg-muted', sizeClasses[size])}>
{imageUrl ? (
<img src={imageUrl} alt={name} className="rounded-full" />
) : (
<span>{name.charAt(0).toUpperCase()}</span>
)}
</div>
)
}
4.5 Feature Components
責務: 特定機能のビジネスロジックを含むコンポーネントです。API呼び出し、状態管理、業務処理を担当します。
設計ポイント:
features/{機能名}/components/に配置してください- 状態管理戦略を明確に決定してください
- Server Actionsを活用してミューテーションを実装してください
- エラーハンドリングを適切に行ってください
// features/users/components/user-profile.tsx の例
'use client'
import { useSuspenseQuery } from '@tanstack/react-query'
import { useUser } from '../hooks/use-user'
export function UserProfile({ userId }: { userId: string }) {
const { user } = useUser(userId)
return (
<div className="space-y-4">
<h2 className="text-xl font-bold">{user.name}</h2>
<p className="text-muted-foreground">{user.email}</p>
</div>
)
}
4.6 Route Components
責務: Next.js App Routerのルーティングに対応するコンポーネントです。ページの構成とデータフェッチを担当します。
設計ポイント:
- 基本的にServer Componentとして実装してください
async/awaitで直接データフェッチを行ってくださいloading.tsxとerror.tsxを配置してくださいgenerateMetadataでSEO対応してください
// app/users/[id]/page.tsx の例
import { Suspense } from 'react'
import { UserProfile } from '@/features/users/components/user-profile'
import { UserProfileSkeleton } from '@/features/users/components/user-profile-skeleton'
interface Props {
params: { id: string }
}
export default function UserPage({ params }: Props) {
return (
<main className="container py-8">
<Suspense fallback={<UserProfileSkeleton />}>
<UserProfile userId={params.id} />
</Suspense>
</main>
)
}
export async function generateMetadata({ params }: Props) {
const user = await fetchUser(params.id)
return { title: `${user.name}のプロフィール` }
}
5. Server/Client Component判定
コンポーネント作成時は、必ずServer/Client境界を判定してください。
判定基準
| 特性 | Server Component | Client Component |
|---|---|---|
| データフェッチ | ✅ 直接async/await | ❌ useQuery等が必要 |
| useState/useEffect | ❌ 使用不可 | ✅ 使用可 |
| イベントハンドラ | ❌ 使用不可 | ✅ 使用可 |
| ブラウザAPI | ❌ アクセス不可 | ✅ アクセス可 |
| 初期バンドル | ✅ 含まれない | ❌ 含まれる |
| 機密情報アクセス | ✅ 安全 | ❌ 露出リスク |
境界設計のベストプラクティス
Client Componentは最小の葉に限定し、Server Componentで可能な限りラップしてください。
// ✅ 良い例:Server ComponentでClient Componentをラップ
// app/dashboard/page.tsx (Server Component)
async function DashboardPage() {
const data = await fetchDashboardData()
return (
<div className="grid gap-4">
{/* 静的な部分はServer Componentで */}
<StatsCards data={data.stats} />
{/* インタラクティブな部分のみClient Component */}
<InteractiveChart data={data.chartData} />
</div>
)
}
6. 状態管理戦略
状態の種類に応じて適切なツールを選択してください。
| 判定順 | 状態の特性(質問) | 採用ツール / 手法 | スコープ | 代表例 |
|---|---|---|---|---|
| 1 | サーバー由来データか? | TanStack Query | サーバー由来 | APIデータ、ユーザー情報 |
| 2 | フォーム入力値か? | React Hook Form + Zod | フォーム | 登録フォーム、検索フォーム |
| 3 | URL同期が必要か? | nuqs(useQueryState) | URL状態 | 検索クエリ、ページ番号 |
| 4 | 単一コンポーネント内で完結するか? | useState | ローカル | モーダル開閉、タブ選択 |
| 5 | 複数コンポーネントで共有し、親子関係が近いか? | 状態引き上げ(Props drilling) | 親子間共有 | 親子間フィルター |
| 6 | 複数コンポーネントで共有し、親子関係が遠いか? | Context | 画面内共有 | テーマ、言語設定 |
| 7 | アプリ全体で利用するか? | Zustand | グローバル | 認証情報、通知 |
7. View層とFoundation層の関係
コンポーネントは大きくView層とFoundation層に分かれます。データフローは一方向(View → Foundation)を維持してください。
8. コンポーネントの分離設計:AIへの依頼プロンプト
要件をもとに、コンポーネント分類を自動で行うAIプロンプトを整備しています。
AIは、必要となる各コンポーネントの一覧と、さらにその後続のコンポーネント作成に必要となるAIへの依頼プロンプトを出力します。
プロンプト使用時は、「## インプット情報」の{}で囲まれた箇所を具体的な要件に置換してからAIに投入します。コンポーネントの分離設計は複雑タスクですので、使用できる最上級の高級LLMモデルの使用を推奨します。
9. AIの応答サンプル
ECサイト管理画面の注文管理機能について、ワイヤーフレームと機能要件からReact/Next.js App Router向けのコンポーネント分離設計をAIに依頼したサンプルです。Claude Codeでの試行結果を添付しています。
まとめ
本ガイドラインの核心は「責務に基づく6カテゴリ分類」と「Server/Client境界の最小化」です。画面仕様書を受け取ったら、まず全コンポーネントを洗い出して分類し、View層(Feature/Route)にビジネスロジックを集約、Foundation層(UI/Form/Layout/Shared)はProps経由の純粋な表示に徹することで、保守性と再利用性を両立させましょう。迷ったときは判定フローに立ち返り、チェックリストで漏れを防ぐことが品質担保の鍵となります。
Appendix:前提技術スタック
| レイヤ | 技術 / ライブラリ | 採用理由 / 前提 |
|---|---|---|
| フレームワーク | Next.js(App Router) | Server / Client Component 分離、RSC、Server Actions を前提とした設計 |
| 言語 | TypeScript | Props / State / API の型安全性を担保するため必須 |
| UI基盤 | shadcn/ui + Radix UI | アクセシビリティ準拠・Headless UI 前提、UI Components の基盤 |
| スタイリング | Tailwind CSS | コンポーネント粒度での責務分離とデザイン一貫性の確保 |
| Variants管理 | class-variance-authority(CVA) | UI Components の variant / size 拡張を標準化 |
| フォーム管理 | React Hook Form | パフォーマンスと非制御入力前提のフォーム設計 |
| バリデーション | Zod | フォーム・Server Actions・型定義 |
| サーバー状態 | TanStack Query | Suspense前提のデータフェッチとキャッシュ管理 |
| URL状態管理 | nuqs | URL = State を前提とした検索・ページング設計 |
| グローバル状態 | Zustand | アプリ全体に影響する最小限の状態管理 |
| ローカル共有状態 | React Context | 画面内限定・疎結合な状態共有用途 |
| テスト(UI) | Storybook | コンポーネント単位の品質担保 |
| テスト(ロジック) | Testing Library / Vitest | 振る舞いベースのテストを前提 |
| データ取得 | fetch / Server Actions | Route / Feature にビジネスロジックを集約 |
| AI支援 | 高性能LLM(Claude / GitHub Copilot等) | コンポーネント分離・設計補助を前提とした利用 |
