Next.js ベストプラクティス
Next.js App Router 開発のための原則
1. サーバーコンポーネント vs クライアントコンポーネント
判断フローチャート
何が必要か?
│
├── useState, useEffect, イベントハンドラ
│ └── クライアントコンポーネント ('use client')
│
├── 直接データフェッチ、インタラクティブ不要
│ └── サーバーコンポーネント (デフォルト)
│
└── 両方?
└── 分割: サーバーペアレント + クライアントチャイルド
デフォルトで
| タイプ | 用途 |
|---|
| サーバー | データフェッチ、レイアウト、静的コンテンツ |
| クライアント | フォーム、ボタン、インタラクティブUI |
2. データフェッチパターン
フェッチ戦略
| パターン | 用途 |
|---|
| Default | 静的 (ビルド時にキャッシュ) |
| Revalidate | ISR (時間ベースのリフレッシュ) |
| No-store | 動的 (毎リクエスト) |
データフロー
| ソース | パターン |
|---|
| データベース | サーバーコンポーネントでfetch |
| API | キャッシュ付きfetch |
| ユーザー入力 | クライアント状態 + サーバーアクション |
3. ルーティングの原則
ファイル規約
| ファイル | 目的 |
|---|
page.tsx | ルートのUI |
layout.tsx | 共有レイアウト |
loading.tsx | ローディング状態 |
error.tsx | エラーバウンダリ |
not-found.tsx | 404ページ |
ルートの構成
| パターン | 用途 |
|---|
ルートグループ (name) | URLに影響させずに整理 |
パラレルルート @slot | 同じ階層の複数ページ |
インターセプト (.) | モーダルオーバーレイ |
4. APIルート
ルートハンドラ
| メソッド | 用途 |
|---|
| GET | データの読み取り |
| POST | データの作成 |
| PUT/PATCH | データの更新 |
| DELETE | データの削除 |
ベストプラクティス
- Zodで入力をバリデーション
- 適切なステータスコードを返す
- エラーを適切に処理
- 可能な限りEdgeランタイムを使用
5. パフォーマンスの原則
画像最適化
- next/image コンポーネントを使用
- ファーストビューにはpriorityを設定
- blur placeholderを提供
- レスポンシブサイズを使用
バンドル最適化
- 重いコンポーネントは動的インポート
- ルートベースのコード分割(自動)
- バンドルアナライザで分析
6. メタデータ
静的 vs 動的
| タイプ | 用途 |
|---|
| 静的export | 固定メタデータ |
| generateMetadata | ルートごとに動的 |
必須タグ
- title (50-60文字)
- description (150-160文字)
- Open Graph画像
- Canonical URL
7. キャッシュ戦略
キャッシュレイヤー
| レイヤー | 制御 |
|---|
| リクエスト | fetchオプション |
| データ | revalidate/tags |
| フルルート | route設定 |
再検証
| 方法 | 用途 |
|---|
| 時間ベース | revalidate: 60 |
| オンデマンド | revalidatePath/Tag |
| キャッシュなし | no-store |
8. サーバーアクション
ユースケース
ベストプラクティス
- 'use server' でマーク
- すべての入力をバリデーション
- 型付きレスポンスを返す
- エラーを処理
9. アンチパターン
| ❌ やらないこと | ✅ やるべきこと |
|---|
| すべてで 'use client' | デフォルトでサーバー |
| クライアントコンポーネントでフェッチ | サーバーでフェッチ |
| ローディング状態をスキップ | loading.tsx を使用 |
| エラーバウンダリを無視 | error.tsx を使用 |
| 大きなクライアントバンドル | 動的インポート |
10. プロジェクト構造
app/
├── (marketing)/ # ルートグループ
│ └── page.tsx
├── (dashboard)/
│ ├── layout.tsx # ダッシュボードレイアウト
│ └── page.tsx
├── api/
│ └── [resource]/
│ └── route.ts
└── components/
└── ui/
覚えておいてください: サーバーコンポーネントには理由があってデフォルトです。まずはサーバーコンポーネントから始め、必要な場合にのみクライアントコンポーネントを追加しましょう。