Skip to content

Next.js 15 動的ルートでの非同期 params 処理エラー解決法

問題概要

Next.js 15のApp Router(appディレクトリ)で動的ルートを使用する際、次のエラーが発生する問題が報告されています:

tsx
Error: Route "/[locale]" used `params.locale`. `params` should be awaited before using its properties.

このエラーは主に、[locale]のような動的ルートセグメントを含むレイアウトやページコンポーネントで、paramsオブジェクトを正しく処理できていない場合に発生します。

典型的な問題の発生箇所

tsx
export default async function RootLayout({
  children,
  params: { locale } // ここでエラーが発生
}: {
  children: React.ReactNode;
  params: { locale: string };
}) {
  // コンポーネントロジック
}

エラー原因

Next.js 15では、動的ルートパラメータ(params)が非同期APIとして変更されました。この変更により:

  1. paramsオブジェクトがPromiseでラップされた形式で渡される
  2. 直接的な分割代入やプロパティアクセスが不可能に
  3. awaitキーワードによる解決が必要に

解決方法

基本的方法: paramsをawaitで待機

<code-group> <code-block title="layout.tsx" active> ```tsx export default async function RootLayout({ children, params // 分割代入せずに受け取る }: { children: React.ReactNode; params: Promise<{ locale: string }>; // Promise型を明示 }) { const { locale } = await params; // awaitで解決

return ( <html lang={locale}> <body>{children}</body> </html> ); }

</code-block>

<code-block title="page.tsx">
```tsx
export default async function Home({
  params
}: {
  params: Promise<{ locale: string }>;
}) {
  const { locale } = await params;
  
  return (
    <div>
      <MainPicture locale={locale} />
    </div>
  );
}
</code-block> </code-group>

APIルートでの対応例

ts
export async function POST(
  req: Request, 
  { params }: { params: Promise<{ id: string }> }
) {
  const { id } = await params;
  // idを使用した処理
}

よくある落とし穴と回避策

1. 静的ファイル配置の問題

動的セグメントディレクトリ内にicon.pngなどの静的ファイルが存在するだけでエラーが発生する場合があります:

diff
app/
├── [lang]/
│   └── layout.tsx
-   └── icon.png // エラー発生源
+ 
+ icon.png // 正しい位置に移動

2. TypeScript型定義の調整

従来の型定義を以下のように修正:

tsx
// 修正前
params: { locale: string };

// 修正後
params: Promise<{ locale: string }>;

3. 自動修正コマンドの利用

Next.js公式のcodemodで一部自動修正可能:

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

実践的サンプルコード

tsx
import { TranslationsProvider } from "@/components/TranslationsProvider";
import initTranslations from "../i18n";

export default async function LocaleLayout({
  children,
  params,
}: {
  children: React.ReactNode;
  params: Promise<{ locale: string }>;
}) {
  const { locale } = await params;
  const { resources } = await initTranslations(locale, ["common"]);

  return (
    <html lang={locale}>
      <TranslationsProvider resources={resources} locale={locale}>
        <body>{children}</body>
      </TranslationsProvider>
    </html>
  );
}

パフォーマンス最適化

generateStaticParamsと併用することで、事前生成と動的処理を両立可能:

tsx
export function generateStaticParams() {
  return i18nConfig.locales.map((locale) => ({ locale }));
}

なぜこの変更が必要か?

Next.js 15では、動的レンダリングパフォーマンスの最適化のため、ルートパラメータの取得プロセスが非同期化されました:

  1. ストリーミングSSRの最適化
  2. 静的生成と動的レンダリングのシームレスな統合
  3. エッジランタイムでの互換性向上

補足リソース

正しい非同期処理を実装することで、Next.js 15のパフォーマンス改善を享受しつつ、国際化対応など動的ルートを必要とする機能を安定して動作させられます。