返回笔记列表

详解Next.js的App Router

App Router 是 Next.js 的新一代路由系统,基于 React Server Components(RSC 服务端组件),采用文件夹驱动路由,替代旧的 Pages Router,是 Next.js 官方主推的未来标准。它不仅是管理页面,而是管理整个应用的一切。

App Router 是 Next.js 在 13.4 版本中引入的新一代路由系统,放在 app/ 目录,基于 React Server Components(RSC 服务端组件),采用文件夹驱动路由,替代旧的 Pages Router(pages/),是 Next.js 官方主推的未来标准。它不仅是管理页面,而是管理整个应用的一切。

区分:

  • Pages Router(旧):pages/ 目录,文件映射路由,全部默认客户端组件
  • App Router(新):app/ 目录,文件夹映射路由,默认服务端组件

组件模型规则

  • app/ 里所有组件默认 = React 服务端组件(RSC),可以直接async/await 获取数据
  • 运行在服务器,不会打包 JS 到浏览器;不能用 useState/useEffect/window
  • 需要交互(如 useState、useEffect、事件监听)时,在文件顶部写 ‘use client’ 显式声明为客户端组件

路由规则:文件夹定义 URL

app/
├── layout.tsx                # 【根布局】全局布局,必须包含 <html><body>
├── page.tsx                  # 首页 /
├── not-found.tsx             # 全局404兜底页面
├── global-error.tsx          # 整个应用最高级别,捕获根layout报错
├── error.tsx                 # app根层级错误边界
├── loading.tsx               # 首页loading骨架屏
├── template.tsx              # 模板组件,每次路由跳转重建(区别layout持久缓存)
│
├── about/                    # 路由 /about
│   ├── layout.tsx            # /about 嵌套布局
│   ├── page.tsx              # /about 页面主体
│   ├── loading.tsx
│   ├── error.tsx
│   └── not-found.tsx         # 仅当前路由下的局部404
│
├── blog/                     # 路由 /blog
│   ├── layout.tsx
│   ├── page.tsx              # /blog 文章列表页
│   ├── loading.tsx
│   ├── error.tsx
│   │
│   └── [slug]/               # 动态路由 /blog/:slug
│       ├── page.tsx          # /blog/xxx 文章详情
│       ├── loading.tsx
│       ├── error.tsx
│       └── not-found.tsx
│
├── (admin)/                  # 路由分组:括号内名称不参与URL,仅用来归类代码
│   ├── layout.tsx            # 管理后台统一布局
│   ├── dashboard/
│   │   └── page.tsx          # 访问地址依然是:/dashboard (没有admin)
│   └── settings/
│       └── page.tsx          # 访问地址:/settings
│
├── api/                      # App Router API路由
│   └── hello/
│       └── route.ts          # 接口: /api/hello 处理 GET/POST/PUT/DELETE 请求
│
├── chat/                      # App Router API路由
│   └── new/
│       └── route.ts          # 接口: /chat/new 处理 GET/POST/PUT/DELETE 请求
│
├── @modal/                   # 并行路由 Parallel Routes(插槽路由)
│   └── (.)photo/             # 拦截路由 Intercepting Routes
│       └── page.tsx
│
└── favicon.ico               # 内置图标约定文件

说明

  • page.tsx,唯一对外可访问页面入口,没有 page 就无法访问该路由
  • template.tsx 类似layout,但每次导航强制重新挂载组件,状态重置
  • 作用域向上继承:子路由没有写 loading.tsx,会向上就近寻找父目录的 loading;error.tsx / not-found.tsx / layout.tsx 遵循同样继承规则
  • error.tsx、global-error.tsx 强制要求 ‘use client’

关于layout.tsx

layout.tsx 作用于当前目录及其所有子路由,会自动包裹同层级和子层级的页面,并且在页面切换时不会重新渲染,极大提升了性能和用户体验。 根 layout 必须有 html/body; layout.tsx 不支持 async,只有 page.tsx 可以写 async function Page

关于Route Handler

在 app 目录下的任意文件夹中,创建一个名为 route.js 或 route.ts 的文件,就是Route Handler。 上图中两个文件夹中的route.ts本质一样:都是Route Handler。api/ 只是常见约定,用来存放接口文件。 作用:处理某个 URL 上的 HTTP 请求 Route Handler = App Router 里的后端接口入口。

  • 浏览器/fetch 访问某个路径(如 GET /chat/newPOST /api/chat
  • Next 找到对应目录下的 route.ts
  • 调用你导出的方法:GETPOSTPUTDELETE
  • 你返回 Response / NextResponse(JSON、重定向、流等)

page.tsx不属于Route Handler,page.tsx(用于渲染页面UI);而Route Handler用于处理 HTTP 请求,一般不渲染页面。 同一路径下也不能同时有 page.tsx 和 route.ts。否则会导致冲突。

为什么不能共存? 因为 page.tsx 和 route.ts 都用来处理同一个路由路径:

  • page.tsx:告诉 Next.js 这个路径要渲染一个 UI 页面(返回 HTML)
  • route.ts:告诉 Next.js 这个路径要作为一个 API 端点(返回 JSON、文件等)

一个路由段(segment)不能同时承担"渲染页面"和"处理 API"两种职责,这在设计上会造成歧义。

App Router 核心优势

  • 原生嵌套布局,不用自己封装布局组件
  • 流式渲染 Streaming,页面分段输出 HTML,提升 LCP 性能
  • 组件级别数据获取:直接 async/await,不再需要 getStaticProps/getServerSideProps
  • 细粒度缓存策略(fetch 缓存、Router Cache)
  • 内置 loading、error、404,开箱即用
  • 服务端组件减少客户端 JS 体积,优化首屏 & SEO
  • Server Actions:直接在组件写后端逻辑,简化全栈开发
next.js