人人都会AI编程

Pages Router 与 App Router 差异

更新时间:2026-07-11

Next.js 在很长一段时间内使用 pages 目录作为路由系统的入口,即 Pages Router。从 v13 开始,Next.js 引入了全新的 App Router,基于 app 目录和 React Server Components 构建,标志着 Next.js 路由和数据获取范式的根本性升级。理解两者的差异,是正确使用 Next.js 和评估老旧项目改造的前提。

Pages Router 回顾

Pages Router 通过文件系统约定(pages/about.tsx/about)自动生成路由,每个页面是一个 React 组件。它的核心机制包括:

  • 静态生成 (SSG):通过 getStaticProps 在构建时获取数据。
  • 服务端渲染 (SSR):通过 getServerSideProps 在每次请求时获取数据。
  • 客户端渲染 (CSR):页面中组件可直接使用客户端 Hook(useStateuseEffect 等)。
  • 全局 App 和 Document_app.tsx_document.tsx 用于注入全局样式、脚本等。
  • API 路由pages/api 目录下文件即服务端函数。

这种方式概念简单,学习成本低,但存在一些局限性:数据获取与组件耦合较紧,布局复用不够灵活,且整个页面难以自动实现更细粒度的流式渲染。

App Router 新特性

App Router 使用 app 目录,核心是基于 React Server Components(RSC) 的架构。主要变化如下:

1. 路由定义
使用文件夹和文件命名约定:app/dashboard/page.tsx 映射到 /dashboardapp/dashboard/layout.tsx 为该路由的共享布局。

2. 服务端组件默认
所有组件默认为服务端组件,在服务器上运行,不发送 JavaScript 到客户端。需要交互性时,才用 'use client' 指令标记为客户端组件。

3. 数据获取
不再需要 getStaticProps / getServerSideProps,而是直接在异步服务端组件中使用 async/await 获取数据,天然支持 Streaming。

// app/posts/page.tsx
export default async function PostsPage() {
  const posts = await fetch('https://api.example.com/posts'); // 自动缓存
  return <PostList posts={posts} />;
}

4. 布局与嵌套
通过 layout.tsx 实现嵌套布局,布局在路由切换时保持状态且不重新渲染,大幅提升导航性能。

5. 流式传输与 Suspense
支持页面级的流式 SSR:使用 loading.tsx 或手动 <Suspense> 边界,实现先渲染外壳、后填充独立数据块的渐进式渲染。

6. 全新的 Server Actions
允许服务端函数直接在客户端组件中调用,简化表单提交等操作,无需手动创建 API 路由。

核心差异对比

| 维度 | Pages Router | App Router |
|------|--------------|------------|
| 组件默认运行环境 | 客户端组件(可用 Hook) | 服务端组件(零客户端 JS) |
| 数据获取方式 | getStaticProps / getServerSideProps | 异步组件 + fetch(自动去重与缓存) |
| 布局 | 手动在 _app.tsx 或页面中处理 | 声明式嵌套布局 layout.tsx,路由切换保留状态 |
| 客户端组件 | 所有组件都可交互 | 需 'use client',仅在需要交互时标记 |
| 流式渲染 | 不支持(页面整体输出) | 通过 <Suspense>loading.tsx 原生支持 |
| API 路由 | pages/api | app/api,同时支持 Route Handlers |
| 元数据 | 通常使用 <Head>next/head | 通过 Metadata API 或 generateMetadata |
| 学习曲线 | 低,概念简单 | 中高,需理解 Server/Client Components 边界 |

迁移与选择建议

  • 新项目建议直接使用 App Router。Next.js 团队已将主要开发精力放在 App Router 上,RSC 架构是目前前端渲染的最优方案之一。
  • 旧项目稳定运行不必强行迁移。Pages Router 会长期维护,两者可以共存(pagesapp 目录同时存在时,App Router 优先匹配)。
  • 渐进式迁移:可从部分路由开始,例如将数据密集的列表页迁移到 App Router 获得流式加载优势,同时保留简单宣传页在 Pages Router。

实用代码示例对比

Pages Router 博客列表页:

// pages/posts.tsx
export async function getStaticProps() {
  const res = await fetch('https://api.example.com/posts');
  return { props: { posts: await res.json() } };
}
export default function Posts({ posts }) {
  return <PostList posts={posts} />;
}

App Router 对应实现:

// app/posts/page.tsx
export default async function Posts() {
  const posts = await fetch('https://api.example.com/posts', {
    next: { revalidate: 60 } // 增量静态再生 (ISR) 时间
  }).then(res => res.json());
  return <PostList posts={posts} />;
}

App Router 版本代码更直接,网络请求与组件天然结合,并且基于 fetch 的缓存策略(revalidateforce-cache)取代了静态生成配置项。


理解这两种路由系统的差异,能够帮助你根据项目需求、团队熟悉程度和性能目标作出合理的技术选择。无论采用哪种方案,Next.js 都能提供坚实的生产级 React 框架支持。