第 2 章
ルーティングとデータフェッチ・キャッシュ
Next.js App Router では、フォルダ構造がそのままルーティングになり、コンポーネントの中で非常にシンプルにデータをフェッチできます。さらに、ページの読み込み速度を最大化するために強力なキャッシュ機構が備わっています。
第2章では、App Router のルーティング構造、データ取得方法、そして複雑な「4つのキャッシュ」について図解で解説します。
1. App Router のルーティング構造
フォルダ名がURLパスになり、そのフォルダ内に配置する特別なファイル名によって役割が決まります。
page.tsx: そのルートの固有UI(ページ本体)。layout.tsx: 複数のページで共有されるUI(ヘッダー、サイドバーなど)。再レンダリングされず状態が維持されます。loading.tsx: ページの読み込み中に表示されるローディングUI(自動的にReact Suspenseでラップされます)。error.tsx: エラー発生時に表示される代替UI。
2. Server Components でのデータフェッチ
RSC(Server Components)では、コンポーネント自体を async 関数にすることで、useEffect や fetch を使ったフックなしで直接データを非同期で取得できます。
// サーバーコンポーネントなので、async/await が直接使える
export default async function PostsPage() {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
return (
<div>
<h1>記事一覧</h1>
<ul>
{posts.map((post: any) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
);
}
3. Next.jsの「4つのキャッシュ」と判定フロー(図解)
Next.jsには、パフォーマンス向上とAPIへの負荷を減らすため、4つの独立したキャッシュシステムが存在します。
キャッシュの概要
| キャッシュ名 | 対象 | 保存場所 | 目的 |
|---|---|---|---|
| Request Memoization | 同一リクエスト内の fetch 重複 |
サーバーメモリ | 1回のリクエスト中で同じAPI呼び出しをまとめる |
| Data Cache | 異なるリクエスト間のAPIデータ | サーバーのディスク/メモリ | データベースやAPIのデータを保存して再利用する |
| Full Route Cache | ページ全体のHTMLとRSC Payload | サーバーのディスク | ビルド時や初回アクセス時に静的にページを丸ごと生成する |
| Router Cache | 画面遷移時のページデータ | ブラウザメモリ | ユーザーが画面遷移する際の待ち時間をゼロにする |
データ取得とキャッシュ判定フロー
flowchart TD
Req[ページをリクエスト] --> RC{1. Router Cache
ブラウザ内にキャッシュはあるか?} RC -->|Yes| ClientRender[キャッシュから即座に画面描画 ✅] RC -->|No (サーバーへリクエスト)| FRC{2. Full Route Cache
静的生成されたHTMLはあるか?} FRC -->|Yes| ReturnHTML[HTML/Payloadを返す] FRC -->|No (動的処理)| RM{3. Request Memoization
同一リクエスト内で同じfetchを実行済か?} RM -->|Yes| ReturnMemo[メモリから結果を返す] RM -->|No| DC{4. Data Cache
前回のAPI取得データがあるか?} DC -->|Yes (かつ有効期限内)| ReturnData[ディスクからデータを返す] DC -->|No (またはキャッシュ無効)| FetchAPI[実際の外部API / データベースから取得] FetchAPI --> SaveDC[Data Cache に保存] SaveDC --> SaveRM[Request Memoization に保存] ReturnHTML --> ClientRender ReturnMemo --> ClientRender ReturnData --> ClientRender style Req fill:#eff6ff,stroke:#3b82f6,stroke-width:2px,color:#1e3a8a style ClientRender fill:#f0fdf4,stroke:#22c55e,stroke-width:2px,color:#14532d
ブラウザ内にキャッシュはあるか?} RC -->|Yes| ClientRender[キャッシュから即座に画面描画 ✅] RC -->|No (サーバーへリクエスト)| FRC{2. Full Route Cache
静的生成されたHTMLはあるか?} FRC -->|Yes| ReturnHTML[HTML/Payloadを返す] FRC -->|No (動的処理)| RM{3. Request Memoization
同一リクエスト内で同じfetchを実行済か?} RM -->|Yes| ReturnMemo[メモリから結果を返す] RM -->|No| DC{4. Data Cache
前回のAPI取得データがあるか?} DC -->|Yes (かつ有効期限内)| ReturnData[ディスクからデータを返す] DC -->|No (またはキャッシュ無効)| FetchAPI[実際の外部API / データベースから取得] FetchAPI --> SaveDC[Data Cache に保存] SaveDC --> SaveRM[Request Memoization に保存] ReturnHTML --> ClientRender ReturnMemo --> ClientRender ReturnData --> ClientRender style Req fill:#eff6ff,stroke:#3b82f6,stroke-width:2px,color:#1e3a8a style ClientRender fill:#f0fdf4,stroke:#22c55e,stroke-width:2px,color:#14532d
キャッシュの制御方法
開発者は fetch のオプションでキャッシュの挙動をコントロールできます。
// キャッシュを強制的に保存する(デフォルト:SSG向け)
fetch('https://api.example.com/data', { cache: 'force-cache' });
// キャッシュを一切使わず、毎回最新データを取得する(SSR向け)
fetch('https://api.example.com/data', { cache: 'no-store' });
// 3600秒間(1時間)はキャッシュを再利用し、それを過ぎたらバックグラウンドで再検証する(ISR向け)
fetch('https://api.example.com/data', { next: { revalidate: 3600 } });
まとめ
- App Router はフォルダ名がルーティングになり、
layout.tsxやpage.tsxを組み合わせてページを組み立てる。 - Server Components では
async/awaitを用いて、サーバー上で直接かつ安全にデータを取得可能。 - Next.jsの 4つのキャッシュ は、ブラウザ(Router Cache)からサーバーのAPI取得(Data Cache)まで細かく連携し、高速化とサーバー負荷の軽減に貢献している。