🍒

Next.js15.3.0で作ってたら、paramsが非同期処理になってた

に公開

はじめに

大体 Next.js の最新バージョンで軽いリポジトリを作って検証したりするのですが、普通にダイナミックルーティングで実装していたらエラーが出たので、その内容と対応方法をまとめてみました。

エラー内容

Console Error
A param property was accessed directly with params.date. params is now a Promise and should be unwrapped with React.use() before accessing properties of the underlying params object. In this version of Next.js direct access to param properties is still supported to facilitate migration but in a future version you will be required to unwrap params with React.use().

和訳
コンソールエラー
param プロパティに params.date で直接アクセスしました。params オブジェクトのプロパティにアクセスする前に、React.use() でアンラップする必要があります。Next.jsのこのバージョンでは、移行を容易にするためにparamプロパティへの直接アクセスをサポートしていますが、将来のバージョンでは paramsReact.use() でアンラップする必要があります。

実装例

エラーになる実装

"use client";

type PageProps = {
  params: {
    date: string;
  };
};

export default function TodoPage({ params }: PageProps) {
  const { date } = params;
・・・(省略)

正しい実装(Next.js 15以降)

"use client";

type PageProps = {
  params: Promise<{ //Promiseを書く
    date: string;
  }>;
};

export default function TodoPage({ params }: PageProps) {
  const { date } = use(params); //useを使う
・・・(省略)

公式ドキュメント

公式ドキュメントに書いてありました!

Next.js 15のアップグレードガイド(Upgrade Guide)

Next.js 15のアップグレードガイド(Upgrade Guide)には、以下のように記載されています。

Previously synchronous Dynamic APIs that rely on runtime information are now asynchronous:

  • cookies
  • headers
  • draftMode
  • params in layout.js, page.js, route.js, default.js, opengraph-image,twitter-image, icon, and apple-icon.
  • searchParams in page.js

To ease the burden of migration, a codemod is available to automate the process and the APIs can temporarily be accessed synchronously.

和訳

ランタイム情報に依存する動的APIは、以前は同期的であったが、現在は非同期的である:

  • cookies
  • headers
  • draftMode
  • layout.js、page.js、route.js、default.js、opengraph-image、twitter-image、icon、apple-iconのparams
  • page.jsのsearchParams

移行の負担を軽減するため、プロセスを自動化するcodemodが用意されており、一時的にAPIに同期してアクセスできる。

https://nextjs.org/docs/app/guides/upgrading/version-15#async-request-apis-breaking-change

Dynamic Routes

公式ドキュメントの「Dynamic Routes」ページには次のように記載されています。

Since the params prop is a promise. You must use async/await or React's use function to access the values. In version 14 and earlier, params was a synchronous prop. To help with backwards compatibility, you can still access it synchronously in Next.js 15, but this behavior will be deprecated in the future.

和訳

params propはpromiseである。値にアクセスするには、async/awaitかReactのuse関数を使う必要があります。バージョン14以前では、paramsは同期propでした。後方互換性を保つために、Next.js 15でも同期的にアクセスできますが、将来的にはこの動作は廃止される予定です。

https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes#good-to-know

解説

Next.js15では、App Routerの内部仕様が変更され、動的ルートで渡されるparamsが非同期(Promise)になりました。

従来は下記のコードように書けていましたが、

type PageProps = {
  params: { id: string };
};

Next.js15以降では、これを以下のように書く必要があります。

type PageProps = {
  params: Promise<{ id: string }>;
};

そしてparamsを直接扱うには、use()関数で展開する必要があります。

const { id } = use(params);

さいごに

変わっていることに全然気がつきませんでした。今回このような変更があったことを知れてよかったです。

Discussion