第1部:アプリケーション設計 Step 2 / 24

コンポーネント設計

Reactアプリはコンポーネントの組み合わせで構成されます。再利用可能な部品として設計することで、保守性が高く効率的な開発ができます。

コンポーネント設計の考え方

コンポーネント分割の基準

1. 再利用性

複数の場所で使う部品はコンポーネント化

例: ボタン、カード、フォーム入力

2. 単一責任

1つのコンポーネントは1つの役割

例: Header、ArticleCard、LoginForm

3. 適切な粒度

大きすぎず、小さすぎず

例: Buttonは良い、ButtonTextは細かすぎ

4. テスト容易性

独立してテストできる単位

例: ArticleListはArticleCardを使う

フォルダ構成

Next.js推奨構成

src/
├── app/                    # Next.js App Router
│   ├── layout.tsx          # 共通レイアウト
│   ├── page.tsx            # トップページ
│   ├── login/
│   │   └── page.tsx
│   ├── register/
│   │   └── page.tsx
│   └── posts/
│       ├── page.tsx        # 記事一覧
│       ├── new/
│       │   └── page.tsx    # 記事作成
│       └── [id]/
│           ├── page.tsx    # 記事詳細
│           └── edit/
│               └── page.tsx
├── components/             # 再利用コンポーネント
│   ├── ui/                 # 汎用UI
│   │   ├── Button.tsx
│   │   ├── Input.tsx
│   │   └── Card.tsx
│   ├── layout/             # レイアウト系
│   │   ├── Header.tsx
│   │   └── Footer.tsx
│   └── features/           # 機能別
│       ├── auth/
│       │   ├── LoginForm.tsx
│       │   └── RegisterForm.tsx
│       └── posts/
│           ├── ArticleCard.tsx
│           ├── ArticleList.tsx
│           └── ArticleForm.tsx
├── hooks/                  # カスタムフック
│   ├── useAuth.ts
│   └── usePosts.ts
├── lib/                    # ユーティリティ
│   └── api.ts
└── types/                  # 型定義
    └── index.ts

ポイント:components/の下は「用途別」に分けることで、どこに何があるか分かりやすくなります。

ブログアプリのコンポーネント設計

汎用UIコンポーネント

Button

Props: variant, size, onClick, disabled, children

Primary Secondary

Input

Props: type, placeholder, value, onChange, error

Card

Props: children, className

カードコンテンツ

機能コンポーネント

コンポーネント 役割 主なProps
Header ナビゲーション、ログイン状態表示 user, onLogout
LoginForm ログインフォーム onSubmit, isLoading
RegisterForm 新規登録フォーム onSubmit, isLoading
ArticleCard 記事のカード表示 article
ArticleList 記事一覧表示 articles
ArticleForm 記事作成・編集フォーム article?, onSubmit, isLoading

コード例

Button.tsx

type ButtonProps = {
  variant?: 'primary' | 'secondary' | 'danger';
  size?: 'sm' | 'md' | 'lg';
  disabled?: boolean;
  onClick?: () => void;
  children: React.ReactNode;
};

export function Button({
  variant = 'primary',
  size = 'md',
  disabled = false,
  onClick,
  children
}: ButtonProps) {
  const baseStyle = 'rounded font-bold transition';

  const variants = {
    primary: 'bg-blue-600 text-white hover:bg-blue-700',
    secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300',
    danger: 'bg-red-600 text-white hover:bg-red-700',
  };

  const sizes = {
    sm: 'px-3 py-1 text-sm',
    md: 'px-4 py-2',
    lg: 'px-6 py-3 text-lg',
  };

  return (
    <button
      className={`${baseStyle} ${variants[variant]} ${sizes[size]}`}
      disabled={disabled}
      onClick={onClick}
    >
      {children}
    </button>
  );
}

ArticleCard.tsx

import Link from 'next/link';
import { Article } from '@/types';

type ArticleCardProps = {
  article: Article;
};

export function ArticleCard({ article }: ArticleCardProps) {
  return (
    <Link href={`/posts/${article.id}`}>
      <div className="bg-white rounded-lg shadow p-6 hover:shadow-md transition">
        <h2 className="text-xl font-bold mb-2">{article.title}</h2>
        <p className="text-gray-600 text-sm mb-4 line-clamp-2">
          {article.content}
        </p>
        <div className="flex justify-between text-xs text-gray-400">
          <span>{article.author.name}</span>
          <span>{new Date(article.createdAt).toLocaleDateString()}</span>
        </div>
      </div>
    </Link>
  );
}

AIにコンポーネント設計を相談

AIへの指示例

ブログアプリのコンポーネント設計を手伝ってください。

【アプリ概要】
- 認証付きブログアプリ
- 記事のCRUD、ユーザー登録・ログイン

【設計してほしいコンポーネント】
1. 汎用UIコンポーネント(Button, Input, Card, Modal)
2. 機能コンポーネント(Header, LoginForm, ArticleCard等)

【要望】
- TypeScriptで型定義も含めて
- Tailwind CSSを使用
- 再利用しやすい設計で

まとめ

  • コンポーネントは「再利用性」「単一責任」を意識して設計
  • フォルダ構成は「用途別」に整理する
  • 汎用UI(Button, Input等)と機能コンポーネントを分ける
  • Propsの型定義で使い方を明確にする
要件定義の方法 次へ:API設計