Next.jsReact路由

Next.js 路由指南:App Router 常见模式

基于当前 Next.js App Router,梳理静态路由、动态路由、catch-all、route groups、parallel routes 和 route handlers 的使用场景,并说明什么时候还会遇到 Pages Router。

·更新于 ·阅读约 11 分钟·计算中...

现在讨论 Next.js 路由,默认应先站在 App Router 视角。Pages Router 仍然存在,但新项目和官方文档的主线都围绕 app/ 目录展开。对大多数团队来说,先把 page.tsxlayout.tsx、动态段、路由分组和 route handler 理清,比背所有文件约定更重要。

目录

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.tsxerror.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 指南

参考资料

订阅 FreeMac

每周精选:免费 Mac 软件评测、可信来源更新、替代方案和少折腾指南。