【初学者用】Next.js14のgenerateStaticParams()の使い方

# はじめに
Next.jsを勉強し始めた方、混乱してしまう静的ページのビルド。
経験者は何だそんなことよという内容かもしれませんが、ReactからNextjsまで学習ロードマップを進んだ方はかなり悩むポイントでもあるので、本日はこのテーマで解説していきたいと思います。

## getStaticPropsとgetServerSidePropsは廃止されたよ

Next.js 13以降、App RouterというNew Routerの導入により、これまでおなじみだった`getStaticProps`と`getServerSideProps`がなくなりました。「えっ、じゃあどうやって静的生成するの？」ってことで、新しい主役のgenerateStaticParamsの登場です。

## 新しい主役のgenerateStaticParams():metal:

`getStaticProps`の代わりに登場したのが`generateStaticParams()`です。この関数は、動的ルートを持つページの静的生成に使用されます。

他に関連するところを解説しますと、
1. `getServerSideProps` と `getStaticProps` の 廃止
3. `getStaticPaths` は `generateStaticParams` に変更

今回はこの生き残った`generateStaticParams`の解説になるというわけです:point_up:


## そもそもなぜこれらの変更が行われたのか？

これらの変更の背景には、「サーバーコンポーネント」という新しい概念の導入があります。サーバーコンポーネントを理解すると、これらの変更が自然な流れであることがわかります。

### サーバーコンポーネントとは？
今回はこの部分は主題ではないので簡単な解説にとどめます。気になる方はこの記事をご覧ください！

https://qiita.com/Dragon1208/items/feac42eb9668a5f75250

メチャクチャ簡単にいうとサーバーコンポーネントは、サーバー上で実行されるReactコンポーネントです。これにより、**サーバー側で直接データを取得したり、処理を行ったりすることができます。**

### 変更の理由

1. **直接非同期処理が可能に**：
   **サーバーコンポーネント内で直接非同期処理を書けるようになったので**、`getServerSideProps`や`getStaticProps`のような特別な関数を使わなくてもいいよね！ってことですな。まあそりゃそうかと。

2. **柔軟性の向上**：
   `generateStaticParams`の導入により、静的生成するページのパラメータをより柔軟に定義できるようになりました。これは特に、動的ルーティングを使用する際に便利です。この部分を解説していきます。

## generateStaticParams()って何をするの？

簡単に言うと、「動的なURLを持つページを、事前に静的なHTMLとして生成するための関数」です。

例えば、ブログの記事ページ`/posts/[id]`があるとします。この[id]部分に入る値を事前に指定することで、ビルド時に静的なページを生成できるということですね。

## 実際のコードを見てみよう（NextjsとTypeScript使用）


```typescript
// type.ts
export type Post = {
  id: string;
  title: string;
  content: string;
}
```

```typescript
// data.ts
export const posts: Post[] = [
  { id: '1', title: '最初の投稿', content: '内容1' },
  { id: '2', title: '次の投稿', content: '内容2' },
  // さらに投稿が続く...
];
```

```typescript
// app/posts/[id]/page.tsx
import { Post } from '../../types';
import { posts } from '../../data';

export async function generateStaticParams(): Promise<{ id: string }[]> {
  return posts.map((post) => ({
    id: post.id,
    // 各ポストのidを設定。この { id: post.id } が下記paramsに渡る
  }));
}

// ページコンポーネントの型定義
type PostPageProps = {
  params: { id: string }
}

// 実際のページコンポーネント
const PostPage = ({ params }: PostPageProps) => {
  // paramsから渡されたidを使って、該当する投稿を探す
  const post = posts.find((p) => p.id === params.id);

  // 投稿が見つからない場合のエラーハンドリング
  if (!post) {
    return <div>ポストが見つかりません。</div>;
  }

  // 投稿の内容を表示
  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </div>
  );
};

export default PostPage;
```

## コードの詳細な解説

### generateStaticParams()  
3. `export async function generateStaticParams(): Promise<{ id: string }[]>`
   - この関数がキモです。非同期関数として定義されており、静的生成するページのパラメータを返します。
   - 返り値の型を明示的に指定しています。`{ id: string }[]` という形式の配列を返すことを示しています。
</br>

4. `return posts.map((post) => ({ id: post.id }));`
   - 全ての投稿のIDをマップして返しています。
   - これにより、各投稿のIDに対応する静的ページが生成されます。

## この方法のポイント

- `generateStaticParams` が返す値に基づいて、ビルド時に静的ページが生成されます。
- 例えば、投稿が3つあれば、`/posts/1`、`/posts/2`、`/posts/3` という3つの静的ページが生成されます。
- ページコンポーネントは、これらの静的生成されたページ全てで使用されます。
- URLパラメータ（この場合は `id`）は `params` オブジェクトを通じてPostPageコンポーネントに渡されます。

## まとめ

`getStaticProps`から`generateStaticParams()`への移行は、最初は戸惑うかもしれません。でも、使ってみると「あ、これ簡単じゃん！」と思えるはずです。