- Published on
Next.js 入门到进阶:(五) 数据获取
- Authors

- Name
- xiaobai
在 App Router 中,数据获取的方式发生了根本性的变化。这主要得益于 React Server Components (RSC) 的引入。现在,默认情况下,所有的页面组件都是服务端组件。
1. 服务端组件中的数据获取
服务端组件可以直接在组件内部执行异步操作来获取数据,这让代码变得异常简洁和直观。你只需要在函数前加上 async 关键字即可。
让我们来创建一个显示文章列表的页面。
// src/app/posts/page.tsx
type Post = {
id: number;
title: string;
body: string;
};
// 这是一个异步的服务端组件
export default async function PostsPage() {
// 直接在组件中使用 fetch 获取数据
const res = await fetch('https://jsonplaceholder.typicode.com/posts?_limit=10');
const posts: Post[] = await res.json();
return (
<main className="p-8">
<h1 className="text-3xl font-bold mb-6">文章列表</h1>
<ul className="space-y-4">
{posts.map((post) => (
<li key={post.id} className="p-4 border rounded-lg">
<h2 className="text-xl font-semibold">{post.title}</h2>
<p className="text-gray-600 mt-2">{post.body}</p>
</li>
))}
</ul>
</main>
);
}
发生了什么?
PostsPage是一个async函数,它会在服务端执行。fetch请求在服务端发出,获取数据。- 组件在服务端完成渲染,生成最终的 HTML。
- 浏览器收到的是已经包含所有文章内容的完整 HTML 页面。
这种方式既有 SSR 的 SEO 优势,又有简洁的开发体验,并且避免了在客户端和服务器之间传输大量 JSON 数据。
2. 缓存与数据更新
Next.js 对 fetch 函数进行了扩展,使其能够精细地控制缓存策略。
默认缓存策略:静态渲染
默认情况下,Next.js 会尽可能地缓存 fetch 的结果。在上面的例子中,fetch('...') 的结果会在构建时被获取并缓存。之后每次访问 /posts 页面,都会直接返回这个缓存的静态 HTML。这实际上就是静态站点生成 (SSG)。
这对于不经常变化的数据(如博客文章、产品列表)来说是绝佳的性能优化。
按需更新:动态渲染
如果你的数据是实时变化的(例如股票价格、天气信息),或者需要根据用户信息展示不同内容,你就需要让页面进行动态渲染 (即传统的 SSR)。
要强制页面进行动态渲染,你有两种主要方式:
方式一:设置 fetch 的缓存选项
将 fetch 的 cache 选项设置为 'no-store',可以告诉 Next.js 不要缓存这次请求的结果。
// 每次请求都会重新获取数据
const res = await fetch('https://api.example.com/data', { cache: 'no-store' });
方式二:使用动态函数
在页面中使用了某些动态函数,如 headers() 或 cookies(),Next.js 也会自动切换到动态渲染模式。
import { cookies } from 'next/headers';
export default async function ProfilePage() {
const userCookie = cookies().get('user-token');
// ... 因为使用了 cookies(),这个页面会动态渲染
}
定期更新:增量静态再生 (ISR)
如果你希望页面大部分时间是静态的,但需要定期更新以获取最新数据(例如新闻网站首页),可以使用 revalidate 选项。
// 数据会被缓存,但每隔 60 秒会重新生成一次
const res = await fetch('https://.../news', { next: { revalidate: 60 } });
这实现了增量静态再生 (Incremental Static Regeneration - ISR)。用户访问到的始终是静态页面,但 Next.js 会在后台悄悄地重新生成页面,确保数据不会太过时。
3. 客户端组件中的数据获取
虽然服务端组件是 App Router 的核心,但有时你仍然需要在客户端获取数据,例如:
- 基于用户交互的实时搜索。
- 需要频繁轮询更新的数据。
要在客户端获取数据,你需要将组件声明为客户端组件,通过在文件顶部添加 'use client' 指令。
'use client'; // 声明为客户端组件
import { useState, useEffect } from 'react';
type User = {
name: string;
};
export default function UserProfile() {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('/api/user') // 假设你有一个获取用户信息的 API 路由
.then((res) => res.json())
.then((data) => {
setUser(data);
setLoading(false);
});
}, []);
if (loading) return <p>加载中...</p>;
return <h1>欢迎, {user?.name}</h1>;
}
这和传统的 React 数据获取方式(使用 useEffect)完全一样。
总结
Next.js App Router 带来了强大的、以服务端为中心的数据获取模式。
- 服务端组件是默认选择,可以直接使用
async/await获取数据。 - Next.js 扩展了
fetchAPI,通过cache和revalidate选项可以轻松实现 SSG、SSR 和 ISR。 - 对于需要交互和浏览器 API 的场景,可以使用
'use client'创建客户端组件,并使用传统方式获取数据。
理解并善用这些数据获取策略,是构建高性能 Next.js 应用的关键。下一篇,我们将学习如何创建 API 路由,为你的应用构建后端接口。
