Skip to content

数据获取和缓存

¥Data Fetching and Caching

Examples

本指南将引导你了解 Next.js 中数据提取和缓存的基础知识,并提供实际示例和最佳实践。

¥This guide will walk you through the basics of data fetching and caching in Next.js, providing practical examples and best practices.

以下是 Next.js 中数据提取的一个最小示例:

¥Here's a minimal example of data fetching in Next.js:

tsx
export default async function Page() {
  const data = await fetch('https://api.vercel.app/blog')
  const posts = await data.json()
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

此示例演示了在异步 React 服务器组件中使用 fetch API 进行基本的服务器端数据提取。

¥This example demonstrates a basic server-side data fetch using the fetch API in an asynchronous React Server Component.

参考

¥Reference

使用 ORM 或数据库缓存数据

¥Caching data with an ORM or Database

你可以在运行 next build 时使用 unstable_cache API 缓存响应。

¥You can use the unstable_cache API to cache the response when running next build.

tsx
import { unstable_cache } from 'next/cache'
import { db, posts } from '@/lib/db'

const getPosts = unstable_cache(
  async () => {
    return await db.select().from(posts)
  },
  ['posts'],
  { revalidate: 3600, tags: ['posts'] }
)

export default async function Page() {
  const allPosts = await getPosts()

  return (
    <ul>
      {allPosts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

此示例将数据库查询的结果缓存 1 小时(3600 秒)。它还添加了缓存标签 posts,然后可以使用 增量静态再生 使其无效。

¥This example caches the result of the database query for 1 hour (3600 seconds). It also adds the cache tag posts which can then be invalidated with Incremental Static Regeneration.

在多个函数中重用数据

¥Reusing data across multiple functions

Next.js 使用 generateMetadatagenerateStaticParams 等 API,你需要使用在 page 中获取的相同数据。

¥Next.js uses APIs like generateMetadata and generateStaticParams where you will need to use the same data fetched in the page.

如果你正在使用 fetch,则可以通过添加 cache: 'force-cache' 将请求变为 memoized。这意味着你可以安全地使用相同的选项调用相同的 URL,并且只会发出一个请求。

¥If you are using fetch, requests can be memoized by adding cache: 'force-cache'. This means you can safely call the same URL with the same options, and only one request will be made.

需要了解:

¥Good to know:

  • 在以前版本的 Next.js 中,使用 fetch 的默认 cache 值为 force-cache。这在版本 15 中更改为默认值 cache: no-store

    ¥In previous versions of Next.js, using fetch would have a default cache value of force-cache. This changed in version 15, to a default of cache: no-store.

tsx
import { notFound } from 'next/navigation'

interface Post {
  id: string
  title: string
  content: string
}

async function getPost(id: string) {
  const res = await fetch(`https://api.vercel.app/blog/${id}`, {
    cache: 'force-cache',
  })
  const post: Post = await res.json()
  if (!post) notFound()
  return post
}

export async function generateStaticParams() {
  const posts = await fetch('https://api.vercel.app/blog', {
    cache: 'force-cache',
  }).then((res) => res.json())

  return posts.map((post: Post) => ({
    id: String(post.id),
  }))
}

export async function generateMetadata({
  params,
}: {
  params: Promise<{ id: string }>
}) {
  const { id } = await params
  const post = await getPost(id)

  return {
    title: post.title,
  }
}

export default async function Page({
  params,
}: {
  params: Promise<{ id: string }>
}) {
  const { id } = await params
  const post = await getPost(id)

  return (
    <article>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </article>
  )
}

如果你不使用 fetch,而是直接使用 ORM 或数据库,则可以使用 React cache 函数封装数据获取。这将删除重复项并仅进行一次查询。

¥If you are not using fetch, and instead using an ORM or database directly, you can wrap your data fetch with the React cache function. This will de-duplicate and only make one query.

重新验证缓存数据

¥Revalidating cached data

了解有关使用 增量静态再生 重新验证缓存数据的更多信息。

¥Learn more about revalidating cached data with Incremental Static Regeneration.