C
React/API連携/Lesson 15

データフェッチング

30分·theory
このチャプター
1/2
JavaScript

データフェッチング

💡 なぜ学ぶべきなのか?

🎯 サーバーのデータベースからリアルタイム情報を取得して画面に表示できます。
💼 キャッシングにより不要なリクエストを削減し、アプリの速度を大幅に向上させます。
NaverやCoupangのような大手企業の採用で必須のスキルです。
🏢 실무에서는
Coupangの商品一覧、Tossの口座情報、当根マーケットの投稿など、あらゆるリアルタイムデータはAPIデータフェッチングで実装されています。効率的なキャッシング戦略を知らなければ、数百万人のユーザーを処理することはできません。

概念

Next.js 14以降のApp Routerが提供する高度なキャッシングとISR(Incremental Static Regeneration)機能は、モダンWebアプリの必須技術です。大量トラフィックの処理とユーザー体験の最適化に直結しており、Naver・Coupang・Tossのような大企業でも重要なパフォーマンス指標として評価されています。

なぜ重要なのか?

コマース商品一覧のように頻繁に変わるデータをリクエストのたびにサーバーから取得すると、応答時間が3秒を超えて直帰率が50%増加します。また、ニュースサイトやブログのようにコンテンツ更新は必要でもリアルタイム性がさほど求められない場合、適切なrevalidate戦略でCDNコストを70%削減できます。

コアコンセプト

Next.jsのデータフェッチングは「スマート冷蔵庫」に例えられます。冷蔵庫が賞味期限を確認して傷んだものだけ新しく買い直すように、Next.jsはデータの「鮮度」を管理し、古くなったものだけサーバーから再取得します。fetchキャッシングはデータを保存する冷蔵庫の役割を果たし、revalidateは賞味期限を確認するセンサーの役割を担います。

キーポイント

  • fetch()はデフォルトでRequest MemoizationとData Cacheの2段階でキャッシングされる
  • revalidateオプションでデータ鮮度の更新周期を制御(秒単位)
  • App RouterではgenerateStaticParamsと組み合わせることで動的ルーティングまで最適化可能
💻 悪い例 — キャッシングなしで毎回データを取得
// app/products/page.tsx - アンチパターン
export default async function ProductsPage() {
  // 毎回サーバーリクエスト - 遅くて非効率
  const res = await fetch('https://api.example.com/products', {
    cache: 'no-store' // キャッシュ無効化
  });
  const products = await res.json();

  return (
    <div>
      {products.map(product => (
        <div key={product.id}>{product.name}</div>
      ))}
    </div>
  );
}
💻 良い例 — 2025年推奨キャッシング戦略
// app/products/page.tsx - 最適化されたパターン
export default async function ProductsPage() {
  // 1時間ごとにデータ更新、その間はキャッシュを使用
  const res = await fetch('https://api.example.com/products', {
    next: { 
      revalidate: 3600, // 1時間 = 3600秒
      tags: ['products'] // キャッシュタグで選択的に無効化
    }
  });
  const products = await res.json();

  return (
    <div>
      {products.map(product => (
        <div key={product.id}>{product.name}</div>
      ))}
    </div>
  );
}

// app/admin/actions.ts - 管理者が商品更新時にキャッシュ無効化
'use server';
import { revalidateTag } from 'next/cache';

export async function updateProduct(formData: FormData) {
  // 商品更新ロジック...
  
  // 特定のタグのみキャッシュ無効化
  revalidateTag('products');
}
💻 高度な例 — 動的ルーティングと組み合わせた最適化
// app/products/[id]/page.tsx
interface Props {
  params: { id: string };
}

// 人気商品100個はビルドタイムに事前生成
export async function generateStaticParams() {
  const products = await fetch('https://api.example.com/popular-products')
    .then(res => res.json());
  
  return products.map((product: any) => ({
    id: product.id.toString() 
  }));
}

export default async function ProductPage({ params }: Props) {
  // 商品詳細は30分ごとに更新
  const product = await fetch(`https://api.example.com/products/${params.id}`, {
    next: { 
      revalidate: 1800, // 30分
      tags: [`product-${params.id}`]
    }
  }).then(res => res.json());

  return (
    <div>
      <h1>{product.name}</h1>
      <p>価格: {product.price}円</p>
    </div>
  );
}

💡 ⚠️ よくある間違い

  • revalidateの時間を短く設定しすぎてキャッシングの効果が得られない(5秒以下はほぼ不要)
  • キャッシュタグを使わず、キャッシュ全体を破棄せざるを得ない非効率な運用(revalidatePathの乱用)
  • generateStaticParamsrevalidateを組み合わせず、動的ルーティングの最適化を見逃す

💡 🎯 面接対策

Q: Next.jsにおけるISRとSSGの違いと、それぞれをいつ使うか説明してください。
Q: 大量トラフィックの状況でNext.jsのキャッシング戦略をどのように設計しますか?
Q: revalidateTagrevalidatePathの違いと使用シナリオを説明してください。

ヒント: ISRはビルド後もデータを更新できるハイブリッド方式と説明し、実務事例(コマース商品一覧など)を挙げて説明しましょう。キャッシングレベルの違い(Request Memoization vs Data Cache)とタグベース無効化の利点を具体的に述べると高評価につながります。

⚛️ Reactパターン — データフェッチング

データフェッチングをReactでどう使うか、コードを交えてステップごとに学びましょう。
1 🧩 1. データフェッチングが必要なシナリオ
この機能が必要な状況。
2 💻 2. コードの記述
データフェッチングの基本的な使い方。
3 🎨 3. レンダリング結果
ユーザーが見る画面。
4 💡 4. 実践的なヒント
よくある落とし穴とベストプラクティス。

🎮 データフェッチング — ステップごとに理解する

各ステップをクリックして内容を読み、✓ 理解しましたボタンで進捗を確認してください。
🖥️ 実行結果 — レンダリングされたReactコンポーネント
✏️ React 코드 수정하기 (클릭해서 열기)
⚛️ React 18 + Babel Standalone — まず結果を確認し、エディタで自由に編集できます。

確認クイズ

Reactでコンポーネントのマウント時にAPIを呼び出す正しいHookは何ですか?
💡 useEffect(fn, []) はコンポーネントが初めてマウントされたときに一度だけ実行されます。API呼び出しやイベントリスナーの登録などの副作用は useEffect 内で処理します。レンダリング中に直接呼び出すと無限ループが発生する可能性があります。
先に読むとよい概念: React Router
次のおすすめ: React Query (TanStack Query)
データフェッチング - React