现在讨论 Next.js 路由,默认应先站在 App Router 视角。Pages Router 仍然存在,但新项目和官方文档的主线都围绕 app/ 目录展开。对大多数团队来说,先把 page.tsx、layout.tsx、动态段、路由分组和 route handler 理清,比背所有文件约定更重要。
目录
- App Router 的基本心智模型
- 静态路由
- 动态路由
- Catch-all 与可选 Catch-all
- layout.tsx 不是普通包装组件
- Route Groups
- Parallel Routes
- Route Handlers
- 什么时候还会遇到 Pages Router
- 结论
- 参考资料
App Router 的基本心智模型
App Router 用文件系统定义路由,路径和目录结构直接对应:
app/
page.tsx -> /
about/
page.tsx -> /about
blog/
[slug]/
page.tsx -> /blog/:slug
和旧教程最大的差异有两点:
- 页面放在
app/**/page.tsx - 布局由同层或上层
layout.tsx持续包裹
如果你正在处理服务端组件边界,建议结合看 Next.js Server 与 Client Components 指南。
静态路由
固定路径最简单,目录名就是 URL 片段:
app/
pricing/
page.tsx
访问路径就是 /pricing。
export default function PricingPage() {
return <h1>Pricing</h1>
}
动态路由
不知道具体路径值时,用方括号包住目录名:
app/blog/[slug]/page.tsx
在当前 Next.js 文档里,params 是一个 promise,需要 await 之后再取值:
export default async function Page({
params,
}: {
params: Promise<{ slug: string }>
}) {
const { slug } = await params
return <div>{slug}</div>
}
这是这篇旧文最需要更新的地方之一。早期教程里经常直接把 params 当同步对象看,但官方文档已经把异步写法列为主线。
Catch-all 与可选 Catch-all
[...slug]
匹配后续所有路径段:
app/docs/[...slug]/page.tsx
它能匹配:
/docs/setup/docs/react/server-components
此时 slug 会是数组。
[[...slug]]
如果连“没有子路径”的情况也要匹配,就用双层方括号:
app/docs/[[...slug]]/page.tsx
它既能匹配 /docs,也能匹配 /docs/setup。
layout.tsx 不是普通包装组件
App Router 的关键能力之一,是让布局在路由切换时保持共享状态与结构:
app/
dashboard/
layout.tsx
page.tsx
analytics/
page.tsx
/dashboard 和 /dashboard/analytics 都会复用同一层 dashboard layout。适合:
- 后台导航
- 多标签工作区
- 文档站侧栏
如果你的布局里需要局部 loading、错误隔离或更复杂的数据边界,再继续扩展 loading.tsx、error.tsx、并行路由等模式。
Route Groups
Route Group 用括号命名目录:
app/
(marketing)/
about/
page.tsx
它只用于组织代码,不进入 URL,所以最终地址仍然是 /about。这点是 Next.js 官方 Route Groups 文档的明确约定。
它适合:
- 按团队或业务线组织目录
- 多套布局共存
- 某些页面共用一层 layout,另一些页面不共用
要注意两件事:
- 不同 group 不能生成同一个 URL
- 如果不同 group 使用不同根布局,跨组导航可能触发整页重载
Parallel Routes
并行路由更偏进阶。它通过 @slot 命名插槽,在同一布局里同时渲染多个页面片段。
app/
dashboard/
layout.tsx
@team/
page.tsx
@analytics/
page.tsx
在共享 layout 里,你会拿到多个插槽 prop:
export default function Layout({
children,
team,
analytics,
}: {
children: React.ReactNode
team: React.ReactNode
analytics: React.ReactNode
}) {
return (
<>
{children}
{team}
{analytics}
</>
)
}
它常见于:
- dashboard 多面板
- 可深链的 modal
- 需要独立 loading / error 状态的复杂区域
如果你只是普通博客、官网或后台 CRUD,大多数时候不需要并行路由。
Route Handlers
在 app/api/**/route.ts 下可以定义服务端接口:
app/api/posts/route.ts
export async function GET() {
return Response.json({ ok: true })
}
适合:
- 轻量 API
- webhook
- 表单提交中转
- 需要直接放在 Next 应用里的服务端逻辑
如果你想比较 Server Actions 和传统 fetch / handler 的边界,继续看 Next.js Server Actions vs Fetch。
什么时候还会遇到 Pages Router
你仍然会在这些场景看到 pages/:
- 老项目渐进迁移
- 依赖老生态插件或历史代码
- 团队暂时不想动路由结构
但如果是新页面、新模块、新教程,优先基于 App Router 写。否则文章很快就会过时。
结论
- 新项目默认先学 App Router。
- 静态路由、动态路由、catch-all 是基础。
layout.tsx、Route Groups、Parallel Routes 决定复杂应用的组织方式。- 现在的
params写法要按当前官方文档理解,不要照搬旧版同步示例。
如果你下一步是在处理图片优化,可以接着看 Next.js Image 组件指南。如果你在调 hydration 或组件边界,继续看 React Hydration Failed 排障指南 和 Next.js Server / Client Components 指南。
参考资料
继续阅读
React Hydration Failed:原因、定位与修复
系统排查服务器 HTML 与客户端首次渲染不一致的问题,覆盖时间、随机数、浏览器 API、无效 HTML、客户端存储、第三方扩展和 suppressHydrationWarning 的边界。
10 分钟Next.js Server 与 Client Components 怎么选
解释 App Router 中 Server Component 与 Client Component 的执行位置、数据获取、序列化边界和 hydration,并给出缩小客户端 bundle 的组件拆分方法。
14 分钟Motion for React 完整指南:动画、手势与退出效果
从安装和 motion 组件开始,系统掌握 Motion for React 的 variants、拖拽手势、MotionValue、useTransform 与 AnimatePresence,并了解 Next.js 使用方式和性能边界。
订阅 FreeMac
每周精选:免费 Mac 软件评测、可信来源更新、替代方案和少折腾指南。