Next.js 作为一个强大的 React 框架,为开发者提供了两种路由系统:App Router Pages Router。这两种路由系统各有特色,适用于不同的场景。App Router 是 Next.js 13 引入的新路由系统。本文将深入探讨 Page Router 和 Next.js 13+ 的 App Router 的详细对比,包括目录结构、API 处理、数据获取、渲染模式、组件行为等多个方面。


Next.js Page Router vs. App Router 详细对比

1. 目录结构

Page Router(13 之前)

/pages
  ├── index.tsx       # 主页
  ├── about.tsx       # 关于页
  ├── api
  │   ├── user.ts     # API 路由
  │   ├── auth.ts     # API 路由
  • 所有页面 都放在 /pages 目录下

  • API 路由 放在 /pages/api/ 目录下

  • 文件名就是路由路径,如 /pages/about.tsx 访问 /about

App Router(13+)

/app
  ├── layout.tsx      # 根布局(全局生效)
  ├── page.tsx        # 主页
  ├── about
  │   ├── page.tsx    # 关于页
  │   ├── loading.tsx # 加载状态
  │   ├── error.tsx   # 错误状态
  ├── api
  │   ├── user
  │   │   ├── route.ts  # API 路由
  │   ├── auth
  │   │   ├── route.ts  # API 路由
  • 所有页面 放在 /app 目录下

  • 每个页面都需要 page.tsx 文件

  • API 路由必须用 route.ts 文件

  • 布局 layout.tsx 可继承


2. API 路由

Page Router

// pages/api/user.ts
import type { NextApiRequest, NextApiResponse } from 'next';

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  res.status(200).json({ message: "Hello, world!" });
}
  • 直接导出 handler(req, res)

  • 只支持 GET/POST 等传统 HTTP 方法

  • 所有 API 文件放 /pages/api/

App Router

// app/api/user/route.ts
import { NextResponse } from 'next/server';

export async function GET() {
  return NextResponse.json({ message: "Hello, world!" });
}

export async function POST(req: Request) {
  const body = await req.json();
  return NextResponse.json({ data: body });
}
  • 必须创建 route.ts 文件

  • 使用 RequestNextResponse 处理请求

  • 支持 RESTful API 方法(GET、POST、PUT、DELETE)


3. 数据获取(服务器端渲染)

Page Router

export async function getServerSideProps() {
  const res = await fetch('https://api.example.com/data');
  const data = await res.json();

  return { props: { data } };
}

export default function HomePage({ data }) {
  return <div>{data.message}</div>;
}
  • 使用 getServerSideProps 进行服务器端渲染

  • 代码只能运行在服务端,客户端看不到

App Router

export default async function HomePage() {
  const res = await fetch('https://api.example.com/data');
  const data = await res.json();

  return <div>{data.message}</div>;
}
  • 默认服务器端渲染(SSR)

  • 不需要 getServerSideProps,直接 await fetch 即可

  • 可以结合 fetch() 进行缓存优化


4. 组件行为

Page Router

  • 默认所有组件是 客户端组件

  • 只有 getServerSidePropsgetStaticProps 运行在服务器上

App Router

  • 默认是服务器组件(Server Component)

  • 如果要使用 useStateuseEffect,必须加 "use client"

"use client";
import { useState } from "react";

export default function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>Count: {count}</button>;
}

5. 路由导航

Page Router

import { useRouter } from 'next/router';

const router = useRouter();
console.log(router.pathname);
  • 使用 useRouter() 获取当前路由

App Router

import { usePathname } from 'next/navigation';

const pathname = usePathname();
console.log(pathname);
  • 必须用 usePathname() 获取当前路由


6. SEO 处理

Page Router

import Head from 'next/head';

export default function HomePage() {
  return (
    <>
      <Head>
        <title>我的网站</title>
        <meta name="description" content="一个很棒的网站" />
      </Head>
      <h1>欢迎来到我的网站</h1>
    </>
  );
}
  • 使用 <Head> 组件定义 SEO 标签

App Router

import { Metadata } from 'next';

export const metadata: Metadata = {
  title: "我的网站",
  description: "一个很棒的网站",
};

export default function HomePage() {
  return <h1>欢迎来到我的网站</h1>;
}
  • 使用 export const metadata 直接定义 SEO 标签


7. 静态生成(SSG)

Page Router

export async function getStaticProps() {
  const data = await fetchData();
  return { props: { data } };
}
  • 需要 getStaticProps() 生成静态页面

App Router

export default async function Page() {
  const data = await fetchData();
  return <div>{data}</div>;
}
  • 默认支持 SSG,静态生成更自然


8. 优缺点总结

Page Router(13 之前)

App Router(13+)

目录结构

/pages 目录

/app 目录,更清晰

API 处理

pages/api/*.ts

app/api/*/route.ts

数据获取

getServerSideProps

直接 fetch()

组件默认行为

默认 客户端组件

默认 服务器组件

SEO

<Head> 组件

metadata

静态生成

getStaticProps()

直接使用 async 组件

适合的场景

适合小型项目,易于上手

适合大项目,支持更强的性能优化


总结

  • 小型项目:使用 Page Router,简单、易上手

  • 大型项目:使用 App Router,支持更强的性能优化

  • App Router 让服务器端渲染更直观、API 处理更规范、组件默认是服务器组件,减少不必要的 JS 加载,提高性能