3.1.2 如何给成千上万的页面做路由——动态路由
一句话破题
用方括号 [param] 命名文件夹,即可创建动态路由,一套代码服务无限页面。
核心价值
博客有上千篇文章,商城有上万个商品,用户有数百万个主页——你不可能为每个实体手动创建一个 page.tsx。动态路由让一个页面模板匹配无限多的 URL 路径。
动态路由语法
| 语法 | 示例路径 | 匹配 URL | params 值 |
|---|---|---|---|
[slug] | app/blog/[slug]/page.tsx | /blog/hello-world | { slug: 'hello-world' } |
[...slug] | app/docs/[...slug]/page.tsx | /docs/a/b/c | { slug: ['a', 'b', 'c'] } |
[[...slug]] | app/shop/[[...slug]]/page.tsx | /shop 或 /shop/a/b | { slug: undefined } 或 { slug: ['a', 'b'] } |
快速上手
基础动态路由:
app/
└── blog/
└── [slug]/
└── page.tsx # 匹配 /blog/任意内容获取动态参数:
tsx
// app/blog/[slug]/page.tsx
type Props = {
params: { slug: string }
}
export default async function BlogPost({ params }: Props) {
const { slug } = params
// 根据 slug 获取文章数据
const post = await getPostBySlug(slug)
if (!post) {
notFound() // 触发 not-found.tsx
}
return (
<article>
<h1>{post.title}</h1>
<div>{post.content}</div>
</article>
)
}Catch-all 路由
当你需要匹配多级路径时,使用 [...param] 语法:
tsx
// app/docs/[...slug]/page.tsx
// 匹配 /docs/getting-started
// 匹配 /docs/api/authentication/oauth
type Props = {
params: { slug: string[] }
}
export default function DocsPage({ params }: Props) {
// slug 是数组:['api', 'authentication', 'oauth']
const breadcrumb = params.slug.join(' > ')
return <div>当前路径:{breadcrumb}</div>
}静态生成动态路由
对于 SEO 关键页面,可以在构建时预生成所有可能的路径:
tsx
// app/blog/[slug]/page.tsx
// 告诉 Next.js 预先生成哪些路径
export async function generateStaticParams() {
const posts = await getAllPosts()
return posts.map((post) => ({
slug: post.slug,
}))
}
// 页面组件保持不变
export default async function BlogPost({ params }: Props) {
// ...
}搜索参数 vs 路由参数
除了路由参数,还可以通过 URL 查询字符串传递数据:
tsx
// URL: /products?category=electronics&sort=price
type Props = {
params: { id: string }
searchParams: { category?: string; sort?: string }
}
export default function ProductsPage({ searchParams }: Props) {
const { category, sort } = searchParams
return (
<div>
<p>分类: {category}</p>
<p>排序: {sort}</p>
</div>
)
}| 类型 | 用途 | 示例 |
|---|---|---|
| 路由参数 | 标识资源 | /blog/my-post(文章唯一标识) |
| 搜索参数 | 筛选/排序 | /products?sort=price(列表筛选条件) |
AI 协作指南
核心意图:让 AI 帮你创建支持动态内容的页面。
需求定义公式:
- 功能描述:我需要一个 [资源类型] 的详情页
- 交互方式:URL 格式为
/[资源名]/[标识符] - 预期效果:根据 URL 参数获取并展示对应数据
关键术语:[slug]、params、generateStaticParams、notFound、searchParams
交互策略:
- 先让 AI 创建动态路由的文件结构
- 让它实现参数获取和数据请求逻辑
- 补充 404 处理和 loading 状态
- 如需 SSG,让它添加
generateStaticParams
避坑指南
- 动态参数是字符串:即使 URL 是
/post/123,params.id也是"123"而非123 - catch-all 参数是数组:
[...slug]返回的是string[],记得处理空数组情况 generateStaticParams返回值必须是对象数组:[{ slug: 'a' }, { slug: 'b' }]- 动态路由默认是动态渲染:除非使用
generateStaticParams预生成
验收清单
- [ ] 动态路由能正确匹配不同的 URL 路径
- [ ]
params能正确获取到 URL 中的动态部分 - [ ] 无效的动态参数能触发 404 页面
- [ ] 需要 SEO 的页面已配置
generateStaticParams
