在 Next.js 15 中,动态路由参数 params 的处理方式发生了破坏性变更,从直接访问改为 Promise 形式,导致未正确处理时会出现以下错误:
Error: Route "/work/[id]" used `params.id`. `params` should be awaited before using its properties.
为什么会有这个变化?
Next.js 15 将 params 改为 Promise 形式,主要目的是:
- 优化性能,支持流式渲染
- 统一异步数据处理模式
- 为未来并发特性铺路
核心概念:服务器组件 vs 客户端组件
在解决问题前,需明确 Next.js 两种组件类型的区别:
| 组件类型 | 特征 | 标识 |
|---|---|---|
| 服务器组件 | 在服务器运行,无交互逻辑 | 无特殊标识(默认) |
| 客户端组件 | 在浏览器运行,有交互/状态逻辑 | 顶部需添加 'use client' |
解决方案
方法一:async/await(适用于服务器组件)
适用场景:页面(page.tsx)、布局(layout.tsx)等无交互的服务器组件。
// 页面组件示例(app/work/[id]/page.tsx)
export default async function WorkPage({
params
}: {
params: Promise<{ id: string }>
}) {
// 关键:用 await 解析 params
const { id } = await params;
return <h1>工作项目 {id}</h1>;
}
// 布局组件示例(app/work/[id]/layout.tsx)
export default async function Layout({
params,
children,
}: {
params: Promise<{ id: string }>;
children: React.ReactNode;
}) {
const { id } = await params;
return (
<div>
<aside>侧边栏 - 项目 {id}</aside>
<main>{children}</main>
</div>
);
}
方法二:use() 函数(适用于客户端组件)
适用场景:带交互逻辑(点击、状态等)的客户端组件(需标记 'use client')。
// 客户端组件示例(app/work/[id]/components/WorkButton.tsx)
'use client'; // 客户端组件标识
import { use } from 'react'; // 引入 React 19 的 use 函数
export default function WorkButton({
params
}: {
params: Promise<{ id: string }>;
}) {
// 关键:用 use() 解析 params
const { id } = use(params);
const handleClick = () => {
alert(`编辑项目 ${id}`);
};
return <button onClick={handleClick}>编辑项目 {id}</button>;
}
如何选择正确的方法?
| 组件类型 | 如何判断 | 推荐方法 |
|---|---|---|
| 服务器组件 | 无 'use client' 标识 | async/await |
| 客户端组件 | 有 'use client' 标识 | use() 函数 |
具体修改
服务器组件改造
// 修改前(错误)
export default function Page({ params }) {
return <div>{params.id}</div>;
}
// 修改后(正确)
export default async function Page({ params }) {
const { id } = await params; // 新增 await 解析
return <div>{id}</div>;
}
客户端组件改造
// 修改前(错误)
'use client';
export default function Component({ params }) {
return <div>{params.id}</div>;
}
// 修改后(正确)
'use client';
import { use } from 'react'; // 新增导入
export default function Component({ params }) {
const { id } = use(params); // 用 use() 解析
return <div>{id}</div>;
}