Skip to content

在 Next.js 15 中处理动态路由参数

问题描述

升级到 Next.js 15 后,许多开发者在访问动态路由中的 params 时遇到了以下错误提示:

A param property was accessed directly with params.id. 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().

典型的项目结构和问题代码:

/app  
  /product  
    /[id]  
      /page.tsx
typescript
export default async function Page({ params }: { params: { id: string } }) {
  const id = params.id; // 这里会抛出错误
  return <div>Product ID: {id}</div>;
}

解决方案

方案一:使用 React.use() 钩子(推荐)

对于需要在客户端组件中直接使用参数的情况:

typescript
"use client";

import { use } from 'react';

export default function Page({ params }: { params: Promise<{ id: string }> }) {
  const { id } = use(params); 
  return <div>Product ID: {id}</div>;
}

TIP

这种方法利用了 React 的 use() 钩子来解析 Promise,是目前 Next.js 15 推荐的最佳实践。

方案二:在服务端组件中使用 await

如果整个页面都是服务端组件,可以使用 await 直接解析参数:

typescript
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params; 
  return <div>Product ID: {id}</div>;
}

方案三:分离服务端和客户端组件

如果需要在客户端组件中使用参数,可以在服务端组件中先解析参数,然后传递给客户端组件:

typescript
// /product/[id]/page.tsx (服务端组件)
import ProductPage from "./productPage";

export default async function Page({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params;
  return <ProductPage id={id} />;
}
typescript
// /product/[id]/productPage.tsx (客户端组件)
"use client";

export default function ProductPage({ id }: { id: string }) {
  return <div>{id}</div>;
}

技术背景

为什么 params 现在变成了 Promise?

Next.js 15 将 params 改为 Promise 对象是为了支持更灵活的异步数据获取模式。这种变化使得:

  1. 更好的并发处理:允许在等待参数解析时执行其他异步操作
  2. 更清晰的异步边界:明确区分同步和异步操作
  3. 未来兼容性:为后续的 React 和 Next.js 特性做准备

注意

虽然当前版本仍然支持直接访问 params 属性,但在未来的版本中这将不再支持。建议尽早迁移到新的 API。

最佳实践建议

  1. 明确组件类型:根据组件是服务端还是客户端选择合适的参数处理方式
  2. 类型安全:确保 TypeScript 类型定义正确反映 params 的 Promise 特性
  3. 错误处理:考虑在解析参数时添加适当的错误处理机制

总结

Next.js 15 中 params 变为 Promise 是一个有意的破坏性变更,旨在为未来的功能提供更好的基础架构支持。通过使用 React.use()await 来正确解析参数,可以确保代码的兼容性和最佳性能。

typescript
// 示例:完整的参数处理模式
export default async function ProductPage({ 
  params 
}: { 
  params: Promise<{ id: string }> 
}) {
  const { id } = await params;
  
  // 在这里可以安全地使用 id
  return <div>Product ID: {id}</div>;
}

建议开发者在升级到 Next.js 15 后立即更新相关代码,以避免未来版本中的兼容性问题。