Dynamic Segments

当你不知道精确的 segment 名并且想要从动态的数据创建时,你可以使用在请求时填充或者在构建时提前获取的Dynamic Segments(动态路由片段)。

约定

动态路由片段通过中括号包裹的方式创建:[folderName]。例如[id]或者[slug]。

动态路由片段会被当做 paramsprop 传递给layout、page、route以及generateMetadata函数。

例子

举例来说,一个 blog 能够包含这样的路由app/blog/[slug]/page.js。[slug]就是动态的分段路径。

tsx
1export default function Page({ params }: { params: { slug: string } }) {
2  return <div>My Post: {params.slug}</div>
3}
RouteExample 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' }

跟 page 路由的 getStaticPath 类似,我们需要配合generateStaticParams来生成数组结构的数据。

Generating Static Params

generateStaticParams函数可以与动态路由段结合使用,以在构建时静态生成路由,而不是在请求时按需生成。

js
1export async function generateStaticParams() {
2  const posts = await fetch('https://.../posts').then((res) => res.json())
3
4  return posts.map((post) => ({
5    slug: post.slug,
6  }))
7}

generateStaticParams 函数的主要优点是其智能数据检索。如果在 generateStaticParams 函数内部使用 fetch 请求获取内容,则这些请求会自动去重。这意味着在多个 generateStaticParams、Layout 和 Page 中具有相同参数的 fetch 请求只会执行一次,从而减少构建时间。

generateStaticParams会在构建时运行(不是请求时运行)。

Catch-all Segments

Danamic-Segments 能够被展开以用于获取所有的路径分段,使用语法[...folderName]。

举个例子,app/shop/[...slug]/page.js可以捕获到/shop/clothes,或者/shop/clothes/tops等更多路径分段。

RouteExample 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'] }

可选的 Catch-all Segments

可以通过在双方括号来将Catch-all Segments设置为可选:[[...folderName]]。

例如,app/shop/[[...slug]]/page.js将匹配/shop,以及/shop/clothes、/shop/clothes/tops、/shop/clothes/tops/t-shirts。

Catch-all Segments和可选Catch-all Segments之间的区别在于,可选的情况下,没有参数的路由也会被匹配(例如上面例子中的/shop)

RouteExample URLparams
app/shop/[[...slug]]/page.js/shop{}
app/shop/[[...slug]]/page.js/shop/a{ slug: ['a'] }

TypeScript 支持

当使用TypeScript时,我们需要根据配置好的分段路由来定义类型:

js
1export default function Page({ params }: { params: { slug: string } }) {
2  return <h1>My Page</h1>
3}
Routeparams Type Definition
app/blog/[slug]/page.js{ slug: string }
app/shop/[...slug]/page.js{ slug: string[] }
app/[categoryId]/[itemId]/page.js{ categoryId: string, itemId: string }