乐闻世界logo
搜索文章和话题

Next.js 中有哪些数据获取方法?

2月17日 23:32

Next.js 提供了多种数据获取方法,开发者可以根据不同的渲染策略和需求选择合适的方式。以下是 Next.js 中主要的数据获取方法:

Pages Router 数据获取方法

1. getStaticProps

在构建时获取数据,用于静态生成(SSG)。

javascript
export async function getStaticProps(context) { const data = await fetch('https://api.example.com/data').then(r => r.json()); return { props: { data }, revalidate: 60, // 可选:ISR,每 60 秒重新生成 notFound: false, // 可选:返回 404 页面 redirect: { destination: '/login', permanent: false }, // 可选:重定向 }; } export default function Page({ data }) { return <div>{data.content}</div>; }

适用场景:

  • 数据在构建时可用
  • 页面内容不经常变化
  • 需要预渲染以提升 SEO

2. getServerSideProps

在每次请求时获取数据,用于服务器端渲染(SSR)。

javascript
export async function getServerSideProps(context) { const { req, res, query, params } = context; // 可以访问请求和响应对象 const token = req.cookies.token; const data = await fetch('https://api.example.com/data', { headers: { Authorization: `Bearer ${token}` } }).then(r => r.json()); return { props: { data }, // 不支持 revalidate }; } export default function Page({ data }) { return <div>{data.content}</div>; }

适用场景:

  • 数据在请求时才能获取
  • 需要访问请求/响应对象
  • 内容频繁变化

3. getStaticPaths

用于动态路由的静态生成,定义所有可能的路径。

javascript
export async function getStaticPaths() { const posts = await getAllPosts(); return { paths: posts.map(post => ({ params: { slug: post.slug } })), fallback: false, // 或 'blocking' 或 true }; } export async function getStaticProps({ params }) { const post = await getPostBySlug(params.slug); return { props: { post }, }; } export default function BlogPost({ post }) { return <div>{post.title}</div>; }

fallback 选项:

  • false:只返回预生成的路径,其他路径返回 404
  • 'blocking':服务器渲染新路径,等待完成后返回
  • true:立即返回静态页面,后台生成新路径

App Router 数据获取方法

1. 服务器组件中的 fetch

在服务器组件中直接使用 fetch 获取数据。

javascript
async function Page() { const data = await fetch('https://api.example.com/data', { cache: 'force-cache', // 或 'no-store', 'no-cache', 'default' next: { revalidate: 60, // ISR tags: ['data'] // 用于按需重新验证 } }).then(r => r.json()); return <div>{data.content}</div>; }

cache 选项:

  • force-cache:强制使用缓存(默认)
  • no-store:不使用缓存
  • no-cache:每次验证缓存
  • default:使用默认缓存策略

2. 使用 React Server Components

javascript
async function BlogList() { const posts = await fetch('https://api.example.com/posts', { next: { revalidate: 3600 } }).then(r => r.json()); return ( <div> {posts.map(post => ( <PostCard key={post.id} post={post} /> ))} </div> ); }

3. 使用 Suspense 和 Streaming

javascript
import { Suspense } from 'react'; async function SlowComponent() { const data = await fetch('https://api.example.com/slow', { next: { revalidate: 60 } }).then(r => r.json()); return <div>{data.content}</div>; } export default function Page() { return ( <div> <h1>Page Title</h1> <Suspense fallback={<div>Loading...</div>}> <SlowComponent /> </Suspense> </div> ); }

客户端数据获取

1. 使用 useEffect

javascript
'use client'; import { useState, useEffect } from 'react'; export default function ClientDataComponent() { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { fetch('/api/data') .then(res => res.json()) .then(data => { setData(data); setLoading(false); }); }, []); if (loading) return <div>Loading...</div>; return <div>{data.content}</div>; }

2. 使用 SWR

javascript
'use client'; import useSWR from 'swr'; const fetcher = (url) => fetch(url).then(res => res.json()); export default function SWRComponent() { const { data, error, isLoading } = useSWR('/api/data', fetcher, { revalidateOnFocus: false, revalidateOnReconnect: false, dedupingInterval: 60000, }); if (isLoading) return <div>Loading...</div>; if (error) return <div>Error</div>; return <div>{data.content}</div>; }

3. 使用 React Query

javascript
'use client'; import { useQuery } from '@tanstack/react-query'; async function fetchData() { const res = await fetch('/api/data'); return res.json(); } export default function ReactQueryComponent() { const { data, error, isLoading } = useQuery({ queryKey: ['data'], queryFn: fetchData, staleTime: 60000, cacheTime: 300000, }); if (isLoading) return <div>Loading...</div>; if (error) return <div>Error</div>; return <div>{data.content}</div>; }

数据获取最佳实践

1. 选择合适的方法

场景推荐方法
静态内容,构建时可用getStaticProps / SSG
动态内容,需要实时数据getServerSideProps / SSR
需要用户交互客户端数据获取
SEO 重要,内容变化不频繁SSG + ISR
需要访问请求/响应对象getServerSideProps

2. 缓存策略

javascript
// 长期缓存 fetch('/api/data', { cache: 'force-cache', next: { revalidate: 3600 } }); // 短期缓存 fetch('/api/data', { cache: 'no-store' }); // 按需重新验证 fetch('/api/data', { next: { tags: ['data'] } }); // 在 API 路由中重新验证 import { revalidateTag } from 'next/cache'; export async function POST() { revalidateTag('data'); return Response.json({ revalidated: true }); }

3. 错误处理

javascript
export async function getStaticProps() { try { const data = await fetchData(); return { props: { data } }; } catch (error) { return { notFound: true, }; } }

4. 加载状态

javascript
// App Router - 使用 loading.js // app/loading.js export default function Loading() { return <div>Loading...</div>; } // Pages Router - 使用自定义加载组件 export default function LoadingPage() { return <div>Loading...</div>; }

5. 并行数据获取

javascript
// 并行获取多个数据 export async function getStaticProps() { const [posts, users, comments] = await Promise.all([ fetch('/api/posts').then(r => r.json()), fetch('/api/users').then(r => r.json()), fetch('/api/comments').then(r => r.json()), ]); return { props: { posts, users, comments }, }; }

性能优化建议

  1. 使用 ISR:对于需要定期更新的内容,使用 ISR 而不是 SSR
  2. 缓存数据:合理设置缓存时间,减少不必要的请求
  3. 并行获取:使用 Promise.all 并行获取多个数据源
  4. 流式渲染:使用 Suspense 实现流式渲染,提升用户体验
  5. 客户端缓存:使用 SWR 或 React Query 缓存客户端数据
  6. 按需重新验证:使用标签系统按需重新验证数据

通过合理选择和使用这些数据获取方法,可以构建高性能、用户体验良好的 Next.js 应用。

标签:Next.js