动态路由
当你事先不知道确切的路段名称并希望从动态数据创建路由时,你可以使用在请求时填充的动态路段或在构建时填充的 prerendered。
¥When you don't know the exact 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]
。例如,[id]
或 [slug]
。
¥A Dynamic Segment can be created by wrapping a folder's name in square brackets: [folderName]
. For example, [id]
or [slug]
.
动态段作为 params
属性传递给 layout
、page
、route
和 generateMetadata
函数。
¥Dynamic Segments are passed as the params
prop to layout
, page
, route
, and generateMetadata
functions.
示例
¥Example
例如,博客可以包含以下路由 app/blog/[slug]/page.js
,其中 [slug]
是博客帖子的动态分段。
¥For example, a blog could include the following route app/blog/[slug]/page.js
where [slug]
is the Dynamic Segment for blog posts.
export default function Page({ params }: { params: { slug: string } }) {
return <div>My Post: {params.slug}</div>
}
export default function Page({ params }) {
return <div>My Post: {params.slug}</div>
}
路由 | 示例网址 | params |
---|---|---|
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' } |
请参阅 generateStaticParams() 页面以了解如何生成该段的参数。
¥See the generateStaticParams() page to learn how to generate the params for the segment.
很高兴知道:动态段相当于
pages
目录中的 动态路由。¥Good to know: Dynamic Segments are equivalent to Dynamic Routes in the
pages
directory.
生成静态参数
¥Generating Static Params
generateStaticParams
功能可以在构建时与 动态路由段 至 静态生成 路由结合使用,而不是在请求时按需使用。
¥The generateStaticParams
function can be used in combination with dynamic route segments to statically generate routes at build time instead of on-demand at request time.
export async function generateStaticParams() {
const posts = await fetch('https://.../posts').then((res) => res.json())
return posts.map((post) => ({
slug: post.slug,
}))
}
export async function generateStaticParams() {
const posts = await fetch('https://.../posts').then((res) => res.json())
return posts.map((post) => ({
slug: post.slug,
}))
}
generateStaticParams
功能的主要优点是智能检索数据。如果使用 fetch
请求在 generateStaticParams
函数内获取内容,则请求为 自动记忆。这意味着跨多个 generateStaticParams
、布局和页面具有相同参数的 fetch
请求只会发出一次,从而减少构建时间。
¥The primary benefit of the generateStaticParams
function is its smart retrieval of data. If content is fetched within the generateStaticParams
function using a fetch
request, the requests are automatically memoized. This means a fetch
request with the same arguments across multiple generateStaticParams
, Layouts, and Pages will only be made once, which decreases build times.
如果你要从 pages
目录迁移,请使用 迁移指南。
¥Use the migration guide if you are migrating from the pages
directory.
请参阅 generateStaticParams
服务器功能文档 了解更多信息和高级用例。
¥See generateStaticParams
server function documentation for more information and advanced use cases.
捕获所有片段
¥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.
路由 | 示例网址 | params |
---|---|---|
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).
路由 | 示例网址 | params |
---|---|---|
app/shop/[[...slug]]/page.js | /shop | {} |
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.
export default function Page({ params }: { params: { slug: string } }) {
return <h1>My Page</h1>
}
export default function Page({ params }) {
return <h1>My Page</h1>
}
路由 | 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 } |
很高兴知道:将来这可能会由 TypeScript 插件 自动补齐。
¥Good to know: This may be done automatically by the TypeScript plugin in the future.