基于本文回答
0
评论

Next.js 13/14 引入的 app 目录 (App Router) 和 pages 目录 (Pages Router) 有什么本质区别?

知识点图片

Next.js 13/14 引入的 App Router (app 目录) 与传统的 Pages Router (pages 目录) 不仅仅是目录名称的变化,而是底层架构和思维模式的彻底重构

核心区别在于:App Router 是建立在 React Server Components (RSC) 之上的,而 Pages Router 是建立在传统的 SSR/SSG 模式之上的。

以下是它们在六个维度的本质区别:

1. 渲染范式:默认服务端组件 (RSC) vs 默认客户端组件

这是最大的本质区别。

  • Pages Router (pages):

    • 默认全是客户端组件。虽然它支持 SSR(服务端渲染 HTML),但浏览器加载后,所有组件都会经历“水合(Hydration)”过程,React 会在客户端重新执行代码以接管页面。
    • 发送给浏览器的 JavaScript 包(Bundle)较大。
  • App Router (app):

    • 默认全是服务端组件 (Server Components)。这些组件在服务器上渲染成特殊的序列化格式,不会打包进客户端的 JavaScript Bundle 中。
    • 零 Bundle Size:如果一个组件不需要交互(如纯展示的文本、布局),它在客户端不需要任何 JS 代码。
    • 需要交互(useState, useEffect)时,必须显式在文件顶部声明 'use client'

2. 路由与文件系统:文件夹即路由 vs 文件即路由

  • Pages Router:

    • 文件即路由pages/about.js 直接对应 /about
    • 逻辑比较扁平,难以表达复杂的嵌套关系。
  • App Router:

    • 文件夹即路由app/about/page.js 对应 /about
    • 引入了特殊文件约定:每个文件夹下可以包含 layout.js (布局), page.js (页面 UI), loading.js (加载状态), error.js (错误处理), not-found.js (404), route.js (API 端点)。
    • 这种结构让 UI 的各个状态(加载中、报错、布局)与路由逻辑紧密绑定。

3. 数据获取:Fetch API vs 特殊钩子函数

  • Pages Router:

    • 依赖特定的 Next.js 函数getServerSideProps (SSR), getStaticProps (SSG), getInitialProps (Legacy)。
    • 数据获取必须在页面顶层进行,不能在组件内部直接获取数据,导致“Props Drilling”(层层传递数据)问题严重。
  • App Router:

    • 废弃了 getStaticProps 等函数
    • 直接在 Server Component 内部使用标准的 async/awaitfetch
    • 支持组件级数据获取:你可以在 Layout 中获取导航栏数据,在 Page 中获取内容数据,互不干扰,并行请求。
    • 通过 fetch 的配置项控制缓存(例如 cache: 'no-store' 等同于 SSR,force-cache 等同于 SSG)。

4. 布局系统 (Layouts):嵌套与状态保持

  • Pages Router:

    • 原生不支持嵌套布局。通常需要使用 _app.js 或者在页面组件上挂载 getLayout 属性这种“黑客”手段来实现。
    • 路由切换时,如果布局逻辑处理不好,整个页面容易重新渲染,导致状态丢失(例如滚动条位置、输入框内容)。
  • App Router:

    • 原生支持嵌套布局app/dashboard/layout.js 可以包裹 app/dashboard/settings/page.js
    • 状态保持:当在同一布局下的不同页面间导航时(例如从 /dashboard/settings/dashboard/analytics),父级布局 dashboard/layout.js 不会重新渲染,其内部状态(如搜索框输入、侧边栏折叠状态)会被完全保留。

5. 流式传输 (Streaming) 与 Suspense

  • Pages Router:

    • 阻塞式渲染。服务器必须等待所有数据(getServerSideProps)准备好,才能生成 HTML 发送给浏览器。用户在数据加载完成前看到的是白屏。
  • App Router:

    • 原生支持 React Suspense 和 Streaming
    • 服务器可以先发送静态的 HTML shell(如导航栏、页脚),数据加载慢的部分显示 Loading 骨架屏(通过 loading.js<Suspense>),等数据准备好后再通过流式传输补全内容。
    • 这显著提高了 TTFB (Time to First Byte) 和 FCP (First Contentful Paint)。

6. 缓存机制 (Caching)

  • Pages Router:

    • 缓存主要依赖 ISR (Incremental Static Regeneration) 配置,粒度较粗。
  • App Router:

    • 引入了多级缓存系统:
      1. Request Memoization: 同一次渲染中重复的 fetch 请求会自动去重。
      2. Data Cache: 跨请求的数据缓存(类似服务端的 CDN)。
      3. Full Route Cache: 静态路由的 HTML 和 RSC Payload 缓存。
      4. Router Cache: 客户端内存缓存,通过 Prefetch 实现瞬间导航。

总结对比表

特性 Pages Router (pages) App Router (app)
核心架构 传统 SSR/SSG (组件默认需水合) React Server Components (默认服务端)
路由定义 文件路径即 URL 文件夹路径即 URL,page.js 定义 UI
数据获取 getServerSideProps / getStaticProps Async Components + fetch API
布局 (Layout) 困难,需使用 _app.js 或模式 原生支持嵌套,切换页面保留状态
加载体验 全页面阻塞,等待数据 Streaming (流式),渐进式加载 UI
客户端 JS 大小 较大 (所有组件逻辑都下载) 极小 (仅下载 'use client' 组件)
SEO 优秀 优秀 (且元数据 API 更现代化)

结论:该选哪个?

  • 新项目强烈建议使用 App Router。它是 Next.js 的未来,React 官方团队也在向 RSC 方向发展。虽然学习曲线稍陡峭,但能带来更好的性能和开发体验。
  • 老项目:如果没有痛点(如复杂的嵌套布局、极致的性能优化需求),可以继续使用 Pages Router。Next.js 会长期支持两者共存。
右滑查看面试常问