Next.js 15における動的ルーティングパラメータの非同期化対応

# Next.js 15における動的ルーティングパラメータの非同期化対応

Next.js 15では、動的ルーティングパラメータ（`params`）が非同期APIとして変更されました。
実装の際に詰まったので記録として残します！

## 発生する問題

Next.js 15にアップグレードした後、以下のようなエラーメッセージが表示されることがあります：

```
Error: Route "/patients/[id]" used `params.id`. `params` should be awaited before using its properties. 
Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis
```

このエラーは、`params`オブジェクトのプロパティ（例：`params.id`）を直接参照した場合に発生します。

## 問題のあるコード例

```tsx
export default async function PatientDetailPage({ params }: PatientPageProps) {
  try {
    const patient = await prisma.patient.findUnique({
      where: { id: params.id }, // ここがエラーの原因
      // ...
    });
    // ...
  } catch (error) {
    // ...
  }
}
```

## 修正方法

修正方法は簡単です。`params`オブジェクトを`await`キーワードで非同期に解決してから、そのプロパティにアクセスします：

```tsx
export default async function PatientDetailPage({ params }: PatientPageProps) {
  try {
    // paramsを非同期に解決してからidを抽出
    const { id } = await params;
    
    const patient = await prisma.patient.findUnique({
      where: { id }, // 抽出したidを使用
      // ...
    });
    // ...
  } catch (error) {
    // ...
  }
}
```

## 修正例：患者詳細ページ

```tsx
export default async function PatientDetailPage({ params }: PatientPageProps) {
  try {
    // paramsを非同期に解決
    const { id } = await params;
    
    const patient = await prisma.patient.findUnique({
      where: { id },
      include: {
        clinic: true,
        createdBy: {
          select: {
            id: true,
            name: true,
            email: true,
          },
        },
        analysisSessions: {
          take: 5,
          orderBy: {
            sessionDate: "desc",
          },
        },
      },
    });

    if (!patient) {
      notFound();
    }
    
    // 以下、既存のコード...
  } catch (error) {
    // エラーハンドリング...
  }
}
```

## 修正例：患者編集ページ

```tsx
export default async function PatientEditPage({ params }: PatientPageProps) {
  // paramsを非同期に解決
  const { id } = await params;

  // 患者データを取得
  const patient = await prisma.patient.findUnique({
    where: { id },
  });

  // 患者が見つからない場合は404ページを表示
  if (!patient) {
    notFound();
  }

  return (
    // JSXの部分...
  );
}
```

## 技術的解説

Next.js 15では、以下の動的APIが非同期になりました：

- ページ、レイアウト、メタデータAPI、ルートハンドラーに提供される `params` と `searchParams`
- `next/headers` からの `cookies()`, `draftMode()`, `headers()`

この変更により、Next.jsはレンダリングの最適化を改善し、パフォーマンスを向上させることができます。関数が既に `async` でマークされていれば、単に `await` キーワードを追加するだけで対応できます。

## クライアントコンポーネントでの対応

サーバーコンポーネント（上記の例）では `await` を使用しますが、クライアントコンポーネント（`'use client'` でマークされたコンポーネント）では `React.use()` を使用する必要があります：

```tsx
'use client'
import * as React from 'react'

function Page({ params }) {
  // クライアントコンポーネントでの非同期アクセス
  const { id } = React.use(params)
  return <p>ID: {id}</p>
}
```

## 自動修正ツール

Next.jsは、この問題を自動的に修正するためのコードモッドを提供しています：

```bash
npx @next/codemod@canary next-async-request-api .
```

ただし、すべてのケースをカバーできるわけではないため、手動での調整が必要な場合もあります。

## まとめ

Next.js 15では、動的ルーティングパラメータが非同期APIとなりました。この変更に対応するには：

1. パラメータにアクセスする前に `await` キーワードを使用する
2. 分割代入で必要なプロパティを抽出する
3. 抽出したプロパティを使用する

これらの変更を加えることで、Next.js 15の新しい非同期APIモデルに対応し、アプリケーションのパフォーマンスを最大限に引き出すことができます。

## 参考
https://nextjs.org/docs/messages/sync-dynamic-apis#why-this-warning-occurred