App Routerでは、標準的なfetch APIを使って非同期Server Components内で直接データをフェッチします — getServerSidePropsなし、useEffectなし、別々のデータレイヤーなし。Next.jsはfetchをキャッシュコントロール機能で拡張しています。
// app/posts/page.tsx — a Server Component
export default async function Posts() {
const res = await fetch("https://api.example.com/posts"); // runs on the server
const posts = await res.json();
return <ul>{posts.map(p => <li key={p.id}>{p.title}</li>)}</ul>;
}
コンポーネントはサーバー上で実行されるため、データを単にawaitして使用するだけです — クライアント側のuseEffect + useState + ローディング状態の複雑なやり取りよりもはるかに簡単です。
Next.jsはfetchを拡張し、各呼び出しが独自のレンダリング動作を選択できるようにします:
fetch(url, { cache: "force-cache" }); // SSG — cached (default for static)
fetch(url, { cache: "no-store" }); // SSR — fresh every request
fetch(url, { next: { revalidate: 60 } }); // ISR — revalidate every 60s
fetch(url, { next: { tags: ["posts"] } }); // tag for on-demand revalidation
これはApp Routerの統合されたモデルです。ページレベルの戦略を選択するのではなく、データフェッチレベルでキャッシングを制御します。
// ❌ sequential — each awaits the previous (slow waterfall)
const user = await getUser();
const posts = await getPosts();
// ✅ parallel — both start at once
const [user, posts] = await Promise.all([getUser(), getPosts()]);
Promise.allで独立したリクエストを一緒に開始すれば、それらが互いをブロックしません。
"use client";
// for client-side data (e.g. after interaction), use a library like SWR or React Query
const { data } = useSWR("/api/user", fetcher);
Server Componentsはほとんどのニーズをカバーします。クライアント側、対話的、または頻繁に再検証が必要なデータの場合はSWR/React Queryを使用してください。
Next.jsは単一のレンダー内で同一のfetch呼び出しを自動的に重複排除します — そのためレイアウトとページで同じデータをフェッチしても二重リクエストにはなりません。
Server Components内での直接的な非同期データフェッチはApp Routerの最大の簡素化の1つです — ボイラープレートなし、サーバー側の安全なアクセス、自動重複排除、そしてSSG/SSR/ISRの選択肢となるフェッチごとのキャッシング。
独立したフェッチを並列化する方法を知ること(ウォーターフォールを回避する)がパフォーマンスの鍵です。
ジュニアからシニアまで、詳細な回答付きのIT面接質問ライブラリ。
寄付する