my-first-ai-web_问题记录02:Next.js 15 动态路由参数处理解决 `params` 异步问题

241 阅读2分钟

在 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>;
}