Skip to content

动态片段

¥Dynamic Segments

如果你事先不知道确切的路由段名称,并且想要使用动态数据创建路由,则可以使用在请求时填写或在构建时预渲染的动态段。

¥When you don't know the exact route segment names ahead of time and want to create routes from dynamic data, you can use Dynamic Segments that are filled in at request time or prerendered at build time.

惯例

¥Convention

可以通过将文件夹名称括在方括号中来创建动态段:[folderName]。例如,博客可以包含以下路由 app/blog/[slug]/page.js,其中 [slug] 是博客帖子的动态分段。

¥A Dynamic Segment can be created by wrapping a folder's name in square brackets: [folderName]. For example, a blog could include the following route app/blog/[slug]/page.js where [slug] is the Dynamic Segment for blog posts.

tsx
export default async function Page({
  params,
}: {
  params: Promise<{ slug: string }>
}) {
  const { slug } = await params
  return <div>My Post: {slug}</div>
}

动态段作为 params 属性传递给 layoutpageroutegenerateMetadata 函数。

¥Dynamic Segments are passed as the params prop to layout, page, route, and generateMetadata functions.

路由示例 URLparams
app/blog/[slug]/page.js/blog/a{ slug: 'a' }
app/blog/[slug]/page.js/blog/b{ slug: 'b' }
app/blog/[slug]/page.js/blog/c{ slug: 'c' }

捕获所有片段

¥Catch-all Segments

通过在括号 [...folderName] 内添加省略号,可以扩展动态段以捕获所有后续段。

¥Dynamic Segments can be extended to catch-all subsequent segments by adding an ellipsis inside the brackets [...folderName].

例如,app/shop/[...slug]/page.js 将匹配 /shop/clothes,但也会匹配 /shop/clothes/tops/shop/clothes/tops/t-shirts 等。

¥For example, app/shop/[...slug]/page.js will match /shop/clothes, but also /shop/clothes/tops, /shop/clothes/tops/t-shirts, and so on.

路由示例 URLparams
app/shop/[...slug]/page.js/shop/a{ slug: ['a'] }
app/shop/[...slug]/page.js/shop/a/b{ slug: ['a', 'b'] }
app/shop/[...slug]/page.js/shop/a/b/c{ slug: ['a', 'b', 'c'] }

可选的包罗万象的段

¥Optional Catch-all Segments

通过将参数包含在双方括号中,可以使包罗万象的段成为可选:[[...folderName]]

¥Catch-all Segments can be made optional by including the parameter in double square brackets: [[...folderName]].

例如,除了 /shop/clothes/shop/clothes/tops/shop/clothes/tops/t-shirts 之外,app/shop/[[...slug]]/page.js 还会匹配 /shop

¥For example, app/shop/[[...slug]]/page.js will also match /shop, in addition to /shop/clothes, /shop/clothes/tops, /shop/clothes/tops/t-shirts.

catch-all 和可选的 catch-all 段之间的区别在于,使用可选时,不带参数的路由也会被匹配(上例中的 /shop)。

¥The difference between catch-all and optional catch-all segments is that with optional, the route without the parameter is also matched (/shop in the example above).

路由示例 URLparams
app/shop/[[...slug]]/page.js/shop{ slug: undefined }
app/shop/[[...slug]]/page.js/shop/a{ slug: ['a'] }
app/shop/[[...slug]]/page.js/shop/a/b{ slug: ['a', 'b'] }
app/shop/[[...slug]]/page.js/shop/a/b/c{ slug: ['a', 'b', 'c'] }

TypeScript

使用 TypeScript 时,你可以根据配置的路由段添加 params 的类型。

¥When using TypeScript, you can add types for params depending on your configured route segment.

路由params 类型定义
app/blog/[slug]/page.js{ slug: string }
app/shop/[...slug]/page.js{ slug: string[] }
app/shop/[[...slug]]/page.js{ slug?: string[] }
app/[categoryId]/[itemId]/page.js{ categoryId: string, itemId: string }

行为

¥Behavior

  • 由于 params prop 是一个 promise。你必须使用 async/await 或 React 的 use 函数来访问值。

    ¥Since the params prop is a promise. You must use async/await or React's use function to access the values.

    • 在版本 14 及更早版本中,params 是一个同步 prop。为了帮助向后兼容,你仍然可以在 Next.js 15 中同步访问它,但此行为将来会被弃用。

      ¥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.

示例

¥Examples

使用 generateStaticParams

¥With generateStaticParams

generateStaticParams 函数可用于在构建时对路由进行 静态生成 操作,而不是在请求时按需操作。

¥The generateStaticParams function can be used to statically generate routes at build time instead of on-demand at request time.

tsx
export async function generateStaticParams() {
  const posts = await fetch('https://.../posts').then((res) => res.json())

  return posts.map((post) => ({
    slug: post.slug,
  }))
}

generateStaticParams 函数中使用 fetch 时,请求为 自动去重。这避免了对相同的数据布局、页面和其他 generateStaticParams 函数进行多次网络调用,从而加快了构建时间。

¥When using fetch inside the generateStaticParams function, the requests are automatically deduplicated. This avoids multiple network calls for the same data Layouts, Pages, and other generateStaticParams functions, speeding up build time.