Next.js 13+ 推出的 App Router 是一次重大架构升级,彻底改变了数据获取的方式。
它最大的特点是拥抱了 Web 标准 ,不再需要 getStaticProps 和 getServerSideProps 这两个专属函数,而是直接使用 React 核心特性 (如 async/await 组件、use 钩子)来实现数据获取。使用NEXT 写起来越来越"像"React。
一、核心变化:从"生命周期"到"组件形态"
在 App Router 中,页面(Page)和布局(Layout)本身就是 Async 组件 ,可以直接在组件顶层 await 获取数据,逻辑更直观。
| 特性 | Pages Router (旧) | App Router (新) |
|---|---|---|
| 数据获取方式 | 专属 API:getStaticProps / getServerSideProps |
直接 async/await (组件内) |
| 运行环境 | 函数运行时 | 组件所在的渲染边界 (服务端/客户端) |
| 代码位置 | 必须导出单独的函数 | 与组件代码写在一起 |
| 核心思维 | 基于路由的"文件系统" + 数据函数 | 基于组件树的 React 服务器组件 |
二、App Router 里怎么替代?
1. 替代 getStaticProps (静态生成)
在旧方案中,我们用它来在构建时生成静态页面。
新方案:直接在组件顶层 await,并开启缓存。
jsx
// app/posts/page.js (App Router 页面)
import PostList from './PostList'
// 这是一个 Server Component (默认就是),可以直接 async
export default async function PostsPage() {
// 直接在组件里请求数据
// 默认情况下,fetch 会被自动缓存 (等同于 getStaticProps)
const res = await fetch('https://api.example.com/posts')
const posts = await res.json()
return <PostList posts={posts} />
}
2. 替代 getServerSideProps (服务端渲染)
在旧方案中,我们用它来每次请求都获取最新数据。
新方案:使用 fetch 并配置 cache: 'no-store'。
jsx
// app/dashboard/page.js
export default async function DashboardPage() {
// 添加 no-store,每次访问都会重新请求 (等同于 getServerSideProps)
const res = await fetch('https://api.example.com/user-data', {
cache: 'no-store'
})
const userData = await res.json()
return <DashboardContent data={userData} />
}
3. 替代 revalidate (增量静态再生 ISR)
旧方案用 revalidate: 10 来定时更新,新方案更灵活。
jsx
// app/blog/page.js
export default async function BlogPage() {
// 后台每 60 秒重新验证并更新数据
const res = await fetch('https://api.example.com/blog-posts', {
next: { revalidate: 60 }
})
const posts = await res.json()
return <BlogList posts={posts} />
}
三、客户端组件怎么获取数据?
如果是需要在浏览器运行、或依赖用户交互的客户端组件(带 'use client'),不能直接 await,需使用 React 的 use 钩子。
jsx
'use client'
import { use } from 'react'
export default function ClientPost({ promise }) {
// use 可以直接 resolve 一个 Promise
const post = use(promise)
return <div>{post.title}</div>
}
// 在父页面调用
import ClientPost from './ClientPost'
export default function Page() {
// 父组件是 Server Component,可以直接 async
const fetchPost = async () => {
const res = await fetch('...')
return res.json()
}
// 把 Promise 传给客户端组件
return <ClientPost promise={fetchPost()} />
}
三、SSG动态路由有什么变化?
在 Next.js 13+ App Router 里,getStaticPaths 被一个新函数替代了:
✨ 新名字:generateStaticParams
它的作用完全等同于旧的 getStaticPaths ,专门用来处理动态路由 (比如 /posts/[id]、/product/[slug]),告诉 Next.js:
构建时要提前生成哪些页面?
旧版 Pages Router:getStaticPaths
js
// pages/posts/[id].js
export async function getStaticPaths() {
return {
paths: [
{ params: { id: '1' } },
{ params: { id: '2' } },
],
fallback: 'blocking' // 重要
};
}
新版 App Router:generateStaticParams
js
// app/posts/[id]/page.js
// 直接导出这个函数就行
export async function generateStaticParams() {
// 这里返回要预先生成的所有 id
return [
{ id: '1' },
{ id: '2' },
];
}
区别:
- 不用写
paths、params了 - 不用写
fallback了 - 默认就是
fallback: blocking(最常用、最安全的模式)
完整可复制示例
这是 App Router 动态路由 + 静态生成的标准写法:
jsx
// app/posts/[id]/page.js
// 1. 告诉 Next.js 构建时生成哪些页面
export async function generateStaticParams() {
// 你可以在这里请求接口获取所有文章ID
// const res = await fetch('https://api.example.com/posts')
// const posts = await res.json()
// 返回要预先生成的参数列表
return [
{ id: '1' },
{ id: '2' },
{ id: '3' },
];
}
// 2. 页面组件(默认 async 服务端组件)
export default async function PostPage({ params }) {
const { id } = params;
// 自动缓存 = 相当于 getStaticProps
const res = await fetch(`https://api.example.com/posts/${id}`);
const post = await res.json();
return (
<div>
<h1>{post.title}</h1>
<p>{post.content}</p>
</div>
);
}
| 旧版 Pages Router | 新版 App Router | 作用 |
|---|---|---|
getStaticProps |
直接 async await fetch |
构建时获取数据 |
getStaticPaths |
generateStaticParams |
动态路由预生成页面 |
revalidate |
fetch(..., { next: { revalidate: 60 } }) |
定时刷新 |
总结
App Router 的核心思想是 "服务器组件":
- 默认就是服务端,能直接读写文件、调接口、连数据库,无需特殊 API。
fetch自带缓存 ,通过cache和next.revalidate配置,完美覆盖了 SSG、SSR、ISR 所有场景。- 代码更集中,逻辑更清晰,完全符合 React 的未来发展方向。