Next.js 提供了多种灵活的数据获取方式,适应不同场景下的需求,包括服务端渲染(SSR)、静态生成(SSG)、增量静态再生(ISR)和客户端渲染(CSR)。以下是详细说明及代码示例:
文章目录
一、服务端数据获取
1. 静态生成(SSG)
在构建时生成页面,适用于内容不频繁变化的页面(如博客、文档、产品页)。
• 基本用法:getStaticProps
在构建时获取数据并生成静态页面。
// pages/blog.js
export async function getStaticProps() {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
return { props: { posts } };
}
export default function Blog({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
• 动态路由 + SSG:getStaticPaths
生成动态路由的静态页面(如 /posts/[id].js
)。
// pages/posts/[id].js
export async function getStaticPaths() {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
const paths = posts.map((post) => ({ params: { id: post.id } }));
return { paths, fallback: false }; // fallback: 'blocking' 或 true
}
export async function getStaticProps({ params }) {
const res = await fetch(`https://api.example.com/posts/${params.id}`);
const post = await res.json();
return { props: { post } };
}
• 增量静态再生(ISR)
在运行时按需重新生成静态页面。
export async function getStaticProps() {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
return { props: { data }, revalidate: 60 }; // 每60秒最多重新生成一次
}
2. 服务端渲染(SSR)
每次请求时生成页面,适合实时数据(如用户仪表盘)。
• getServerSideProps
在每次请求时运行,生成动态内容。
// pages/user.js
export async function getServerSideProps(context) {
const { req, res } = context;
const user = await getUser(req); // 从请求中获取用户信息
return { props: { user } };
}
export default function UserProfile({ user }) {
return <div>{user.name}</div>;
}
二、客户端数据获取
适用于无需 SEO 或用户交互后加载数据的场景(如搜索框、分页)。
1. 使用 useEffect
+ fetch
在组件挂载后或依赖变化时获取数据。
// components/UserList.js
import { useState, useEffect } from 'react';
function UserList() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch('/api/users')
.then((res) => res.json())
.then((data) => setUsers(data));
}, []);
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
2. 使用数据请求库(如 SWR、React Query)
优化客户端请求(缓存、重试、自动刷新)。
// 使用 SWR
import useSWR from 'swr';
function Profile() {
const { data, error } = useSWR('/api/user', fetcher);
if (error) return <div>Failed to load</div>;
if (!data) return <div>Loading...</div>;
return <div>Hello {data.name}!</div>;
}
三、混合渲染策略
结合服务端和客户端数据获取,优化用户体验。
示例:首屏静态渲染 + 客户端更新
- 使用
getStaticProps
生成静态内容。 - 客户端获取实时数据并更新。
// pages/dashboard.js
export async function getStaticProps() {
const staticData = await fetch('https://api.example.com/static-data');
return { props: { staticData } };
}
function Dashboard({ staticData }) {
const [realTimeData, setRealTimeData] = useState(null);
useEffect(() => {
fetch('/api/real-time')
.then((res) => res.json())
.then((data) => setRealTimeData(data));
}, []);
return (
<div>
<h1>{staticData.title}</h1>
<p>Real-time: {realTimeData?.value}</p>
</div>
);
}
四、API Routes
在 Next.js 中直接创建后端 API,简化全栈开发。
// pages/api/user.js
export default function handler(req, res) {
const user = { name: 'Alice', id: 1 };
res.status(200).json(user);
}
客户端调用:
fetch('/api/user')
.then((res) => res.json())
.then((data) => console.log(data));
五、Next.js 13+ App Router 的新特性
在 app
目录下,支持在组件中直接使用 async/await
获取数据。
// app/page.js
async function getData() {
const res = await fetch('https://api.example.com/data');
return res.json();
}
export default async function Page() {
const data = await getData();
return <div>{data.title}</div>;
}
六、选择策略的对比
方法 | 适用场景 | 优点 | 缺点 |
---|---|---|---|
getStaticProps (SSG) | 内容固定的页面(如博客、文档) | 极快的加载速度,SEO 友好 | 构建时生成,不适合频繁更新 |
getServerSideProps (SSR) | 需要实时数据的页面(如用户仪表盘) | 实时数据,SEO 友好 | 每次请求都需服务器处理,速度较慢 |
客户端获取 | 用户交互后加载数据(如搜索、分页) | 减少服务端压力,灵活 | 首屏加载慢,不利于 SEO |
ISR | 需要定期更新的静态内容(如电商商品页) | 结合静态生成和动态更新 | 首次访问可能需等待再生 |
七、最佳实践
- 优先使用 SSG/ISR:除非必须实时数据,否则优先静态生成。
- 按需混合渲染:首屏使用 SSG/SSR,客户端加载附加数据。
- 缓存 API 请求:通过
revalidate
或 CDN 减少重复请求。 - 错误处理:客户端和服务端均需处理加载状态和错误。
- 性能优化:使用
next/image
优化图片,next/link
预加载路由。
掌握这些方法后,可根据业务需求灵活选择数据获取策略,兼顾性能、SEO 和用户体验。