Next.jsのApp Routerで、Dynamic Routes(例: /items/[id])のページコンポーネントを作成している際に、以下のようなエラーに遭遇したことはありませんか?
Error: Route "/items/[id]" used `params.id`. `params` should be awaited before using its properties. Learn more: [https://nextjs.org/docs/messages/sync-dynamic-apis](https://nextjs.org/docs/messages/sync-dynamic-apis)エラーメッセージは「paramsのプロパティを使う前にawaitしてください」と教えてくれていますが、なぜparamsをawaitする必要があるのでしょうか?
この記事では、このエラーが発生する背景と、コードをどのように修正すればよいかを、具体的な例を交えて分かりやすく解説します。
なぜエラーが起きるのか?非同期化するNext.js
このエラーの根本的な原因は、Next.jsのApp Routerが、パフォーマンス向上のためにコンポーネントのレンダリングを非同期で行うことを前提としている点にあります。
特に、Dynamic RoutesでURLの一部([id]など)を取得するparamsオブジェクトは、その値の解決を待たずにページのレンダリングを開始できるように、Promise(プロミス)のように振る舞うことがあります。
つまり、従来のPages Routerのように、コンポーネントが読み込まれた瞬間にparams.idのような値を同期的に取得しようとすると、「まだ値の解決が終わっていませんよ」とNext.jsに怒られてしまうのです。
解決策:async/awaitでparamsを解決する
解決策はエラーメッセージが示す通り、非常にシンプルです。
- ページコンポーネントを
async関数にする。 paramsオブジェクト自体をawaitで解決してから、その中のプロパティ(idなど)を使用する。
これにより、paramsの値が確実に利用可能になってから、コンポーネントのロジックが実行されることを保証できます。
修正前のコード(エラーが発生)
以下は、paramsを同期的に扱おうとしてエラーになるコードの例です。
// app/items/[id]/page.tsx
// async が付いていない
export default function ItemPage({ params }: { params: { id: string } }) {
// paramsを直接使おうとしているため、ここでエラーが発生する
const item = data.find(d => d.id === params.id);
if (!item) {
return <div>アイテムが見つかりません</div>;
}
return <h1>{item.name}</h1>;
}修正後のコード(解決!)
コンポーネントをasyncにし、paramsをawaitで解決するように修正します。
// app/items/[id]/page.tsx
// 1. コンポーネントを async 関数に変更
export default async function ItemPage({ params }: { params: { id: string } }) {
// 2. params を await で解決し、プロパティを取り出す
const { id } = await params;
// 解決済みのidを使ってロジックを実行
const item = data.find(d => d.id === id);
if (!item) {
return <div>アイテムが見つかりません</div>;
}
return <h1>{item.name}</h1>;
}※Next.jsのバージョンや環境によっては、型定義を { params: Promise<{ id: string }> } のように変更する必要がある場合もあります。
この修正により、paramsが非同期で解決されるのを待ってから処理が進むため、エラーは発生しなくなります。
まとめ
Next.jsのApp Routerでは、パフォーマンスとストリーミングのために非同期処理が基本となっています。
Dynamic Routesでparamsを扱う際は、**「ページコンポーネントはasyncにし、paramsはawaitしてから使う」**と覚えておきましょう。
この新しいNext.jsの常識に慣れることで、よりモダンで高速なWebアプリケーションをスムーズに開発できるようになります。