2025年人気No.1のNext.jsで、最新ツールとウェブを作る！ | エピソード4 データ取得とAPIルート

## 目標
- Next.jsでのデータ取得方法を理解する。
- SSG、SSR、Server Componentsを使ったデータ処理を学ぶ。
- APIルートを作成し、フロントエンドからデータを取得する。

---

## 1. データ取得の方法
Next.jsでは、主に以下の方法でデータを取得できます：
- **Static Site Generation (SSG)**: ビルド時にデータを生成。`getStaticProps`を使用。
- **Server-Side Rendering (SSR)**: リクエストごとにサーバーでデータ取得。`getServerSideProps`を使用。
- **Server Components**: App Routerでの新しい方法。サーバー側で直接データ処理。
このエピソードでは、App RouterのServer Componentsを中心に進めますが、従来の方法も軽く触れます。

---

## 2. Server Componentsでデータ取得
App Routerでは、ページ自体がServer Componentとして動作し、データ取得が簡単です。

### 例：外部APIからデータを取得
`app/page.tsx`を編集して、JSONPlaceholderから投稿を取得：
```tsx
async function fetchPosts() {
  const res = await fetch('https://jsonplaceholder.typicode.com/posts?_limit=5');
  const posts = await res.json();
  return posts;
}

export default async function Home() {
  const posts = await fetchPosts();

  return (
    <div className="min-h-screen flex flex-col items-center justify-center bg-gray-100">
      <h1 className="text-4xl font-bold text-blue-600 mb-4">最新の投稿</h1>
      <ul className="space-y-4">
        {posts.map((post) => (
          <li key={post.id} className="bg-white p-4 rounded shadow">
            <h2 className="text-xl font-semibold">{post.title}</h2>
            <p className="text-gray-600">{post.body}</p>
          </li>
        ))}
      </ul>
    </div>
  );
}
```

**ポイント**：
- `async/await`をページコンポーネント内で直接使用可能。
- サーバー側で実行されるため、クライアントに負担をかけません。

---

## 3. 従来の方法：SSGとSSR
App Router以外の場合のために、`getStaticProps`と`getServerSideProps`も見ておきましょう。

### SSGの例（参考）：
```tsx
// app/sample-static/page.tsx
export async function getStaticProps() {
  const res = await fetch('https://jsonplaceholder.typicode.com/posts?_limit=5');
  const posts = await res.json();
  return { props: { posts } };
}

export default function StaticPage({ posts }) {
  return (
    <div>
      <h1>静的ページ</h1>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
}
```

### SSRの例（参考）：
```tsx
// app/sample-server/page.tsx
export async function getServerSideProps() {
  const res = await fetch('https://jsonplaceholder.typicode.com/posts?_limit=5');
  const posts = await res.json();
  return { props: { posts } };
}

export default function ServerPage({ posts }) {
  return (
    <div>
      <h1>サーバーサイドページ</h1>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
}
```

---

## 4. APIルートの作成
Next.jsでは、`app/api/`内にAPIエンドポイントを作成できます。

### 手順：
1. `app/api/hello/route.ts`を作成し、以下を記述：
   ```ts
   import { NextResponse } from 'next/server';

   export async function GET() {
     return NextResponse.json({ message: 'こんにちは、Next.js APIから！' });
   }
   ```

2. **確認**：
   - `http://localhost:3000/api/hello`にアクセスすると、JSONレスポンスが返る。

### フロントエンドからAPIを呼び出し：
`app/page.tsx`にAPI呼び出しを追加：
```tsx
async function fetchPosts() {
  const res = await fetch('https://jsonplaceholder.typicode.com/posts?_limit=5');
  const posts = await res.json();
  return posts;
}

async function fetchHello() {
  const res = await fetch('/api/hello');
  const data = await res.json();
  return data.message;
}

export default async function Home() {
  const posts = await fetchPosts();
  const helloMessage = await fetchHello();

  return (
    <div className="min-h-screen flex flex-col items-center justify-center bg-gray-100">
      <h1 className="text-4xl font-bold text-blue-600 mb-4">{helloMessage}</h1>
      <ul className="space-y-4">
        {posts.map((post) => (
          <li key={post.id} className="bg-white p-4 rounded shadow">
            <h2 className="text-xl font-semibold">{post.title}</h2>
            <p className="text-gray-600">{post.body}</p>
          </li>
        ))}
      </ul>
    </div>
  );
}
```

---

## 実践：投稿リストページ
- **Homeページ**：外部API（JSONPlaceholder）と自作API（`/api/hello`）からデータを取得し、投稿リストを表示。
- Tailwind CSSでデザインを整える。

---

## エピソード4の終了
- Next.jsでのデータ取得方法（Server Components、SSG、SSR）を学びました。
- APIルートを作成し、フロントエンドから呼び出す方法を習得しました。

**次回のエピソード**：Markdownを使ってブログを構築し、静的コンテンツを扱います。

---

この記事が役に立ったと思ったら、ぜひ「いいね」を押して、ストックしていただければ嬉しいです！次回のエピソードもお楽しみに！