Next.js 14 App Router - データフェッチング
データフェッチの4つの方法
- サーバーで
fetchを使用 - サーバーでサードパーティライブラリを使用
- クライアントで Route Handler 経由
- クライアントでサードパーティライブラリ(SWR, TanStack Query等)
サーバーでの fetch
Next.js はネイティブ fetch を拡張し、キャッシングと再検証の挙動を設定可能。 React は fetch を自動メモ化。
tsx
// app/page.tsx
async function getData() {
const res = await fetch('https://api.example.com/...')
if (!res.ok) {
throw new Error('Failed to fetch data') // 最も近い error.js を起動
}
return res.json()
}
export default async function Page() {
const data = await getData()
return <main>{/* ... */}</main>
}注意:
- Route Handlers 内の
fetchはメモ化されない(React コンポーネントツリーの一部ではないため) - TypeScript で
async/awaitを使うには TypeScript 5.1.3+ と@types/react18.2.8+ が必要
キャッシング
デフォルトでキャッシュ
js
// 'force-cache' がデフォルト(省略可能)
fetch('https://...', { cache: 'force-cache' })POST メソッドも自動キャッシュ(Route Handler 内のPOSTを除く)。
キャッシュからオプトアウト
fetch がキャッシュされない条件:
cache: 'no-store'を指定revalidate: 0を指定- Route Handler 内の POST メソッド
headersやcookiesの使用後const dynamic = 'force-dynamic'セグメント設定fetchCacheセグメント設定でスキップAuthorizationorCookieヘッダー使用(上位に未キャッシュリクエストがある場合)
js
fetch('https://...', { cache: 'no-store' })再検証(Revalidation)
時間ベースの再検証
js
fetch('https://...', { next: { revalidate: 3600 } }) // 最大1時間ごとまたは Route Segment Config:
tsx
export const revalidate = 3600 // 最大1時間ごとオンデマンド再検証
パスベース: revalidatePath
ts
'use server'
import { revalidatePath } from 'next/cache'
export async function action() {
revalidatePath('/posts')
}タグベース: revalidateTag
tsx
// フェッチ時にタグ付け
const res = await fetch('https://...', { next: { tags: ['collection'] } })
// Server Action でタグを再検証
'use server'
import { revalidateTag } from 'next/cache'
export async function action() {
revalidateTag('collection')
}エラー時の挙動: エラーが発生した場合、最後に成功したデータがキャッシュから提供され続ける。
サードパーティライブラリでのフェッチ(サーバー)
fetch を使わないDB・CMS・ORMクライアントの場合:
ts
import { cache } from 'react'
export const getItem = cache(async (id: string) => {
const item = await db.item.findUnique({ id })
return item
})tsx
// app/item/[id]/layout.tsx
import { getItem } from '@/utils/get-item'
export const revalidate = 3600
export default async function Layout({ params: { id } }: { params: { id: string } }) {
const item = await getItem(id)
// ...
}React cache でメモ化 + revalidate セグメント設定でキャッシュ制御。 getItem が複数箇所で呼ばれても、DBクエリは1回のみ。
クライアントでのフェッチ
Route Handler 経由
Client Component から Route Handler を呼び出してデータ取得。 APIトークンなどの機密情報をクライアントに露出しない。
Server Components ではRoute Handlerを呼ぶ必要はない。直接フェッチ可能。
サードパーティライブラリ
- SWR: https://swr.vercel.app/
- TanStack Query: https://tanstack.com/query/latest
独自のメモ化、キャッシング、再検証、ミューテーションAPIを提供。
データフェッチパターン
どこで使うかに応じてフェッチ
同じデータが必要な複数コンポーネントでそれぞれ fetch してOK。 React が自動的にリクエストをメモ化・重複排除。
並列データフェッチ
Promise.all でウォーターフォールを回避:
tsx
async function Page() {
const artistData = getArtist(id)
const albumsData = getAlbums(id)
const [artist, albums] = await Promise.all([artistData, albumsData])
// ...
}