Menu

use cache

use cache 指令允许你将路由、React 组件或函数标记为可缓存。它可以在文件顶部使用,表示文件中的所有导出都应该被缓存,或者在函数或组件顶部内联使用,以缓存返回值。

用法

use cache 目前是一个实验性功能。要启用它,请在你的 next.config.ts 文件中添加 useCache 选项:

next.config.ts
TypeScript
import type { NextConfig } from 'next'
 
const nextConfig: NextConfig = {
  experimental: {
    useCache: true,
  },
}
 
export default nextConfig

值得注意的是: use cache 也可以通过 dynamicIO 选项启用。

然后,在文件、组件或函数级别添加 use cache

// 文件级别
'use cache'
 
export default async function Page() {
  // ...
}
 
// 组件级别
export async function MyComponent() {
  'use cache'
  return <></>
}
 
// 函数级别
export async function getData() {
  'use cache'
  const data = await fetch('/api/data')
  return data
}

use cache 如何工作

缓存键

缓存条目的键是使用其输入的序列化版本生成的,包括:

  • 构建 ID(为每次构建生成)
  • 函数 ID(函数的唯一安全标识符)
  • 可序列化的函数参数(或 props)。

传递给缓存函数的参数,以及它从父作用域读取的任何值,都会自动成为键的一部分。这意味着,只要输入相同,就会重用相同的缓存条目。

不可序列化的参数

任何不可序列化的参数、props 或闭包值将在缓存函数内部变成引用,只能被传递而不能被检查或修改。这些不可序列化的值将在请求时填充,不会成为缓存键的一部分。

例如,缓存函数可以接受 JSX 作为 children prop 并返回 <div>{children}</div>,但它无法检查实际的 children 对象。这允许你在缓存组件内嵌套未缓存的内容。

app/ui/cached-component.tsx
TypeScript
function CachedComponent({ children }: { children: ReactNode }) {
  'use cache'
  return <div>{children}</div>
}

返回值

可缓存函数的返回值必须是可序列化的。这确保缓存的数据可以正确地存储和检索。

构建时的 use cache

当在 layoutpage 的顶部使用时,路由片段将被预渲染,允许它稍后被重新验证

这意味着 use cache 不能与请求时 API(如 cookiesheaders)一起使用。

运行时的 use cache

服务器上,各个组件或函数的缓存条目将被缓存在内存中。

然后,在客户端,从服务器缓存返回的任何内容都将存储在浏览器的内存中,持续时间为会话期间或直到重新验证

重新验证期间

默认情况下,use cache 的服务器端重新验证周期为15 分钟。虽然这个周期对于不需要频繁更新的内容可能很有用,但你可以使用 cacheLifecacheTag API 来配置各个缓存条目应该何时重新验证。

  • cacheLife:配置缓存条目的生命周期。
  • cacheTag:创建用于按需重新验证的标签。

这两个 API 在客户端和服务器缓存层之间集成,这意味着你可以在一个地方配置缓存语义,并使它们在任何地方都适用。

有关更多信息,请参阅 cacheLifecacheTag API 文档。

示例

使用 use cache 缓存整个路由

要预渲染整个路由,请在 layoutpage 文件的顶部添加 use cache。这些片段被视为应用程序中的独立入口点,并且将独立缓存。

app/layout.tsx
TypeScript
'use cache'
 
export default function Layout({ children }: { children: ReactNode }) {
  return <div>{children}</div>
}

导入并嵌套在 page 文件中的任何组件都将继承 page 的缓存行为。

app/page.tsx
TypeScript
'use cache'
 
async function Users() {
  const users = await fetch('/api/users')
  // 遍历用户
}
 
export default function Page() {
  return (
    <main>
      <Users />
    </main>
  )
}

值得注意的是

  • 如果 use cache 仅添加到 layoutpage,则只有该路由片段和导入到其中的任何组件将被缓存。
  • 如果路由中的任何嵌套子项使用动态 API,则路由将选择退出预渲染。

使用 use cache 缓存组件的输出

你可以在组件级别使用 use cache 来缓存该组件内执行的任何获取或计算。只要序列化的 props 在每个实例中产生相同的值,缓存条目就会被重用。

app/components/bookings.tsx
TypeScript
export async function Bookings({ type = 'haircut' }: BookingsProps) {
  'use cache'
  async function getBookingsData() {
    const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)
    return data
  }
  return //...
}
 
interface BookingsProps {
  type: string
}

使用 use cache 缓存函数输出

由于你可以将 use cache 添加到任何异步函数,因此你不仅限于缓存组件或路由。你可能想要缓存网络请求、数据库查询或慢速计算。

app/actions.ts
TypeScript
export async function getData() {
  'use cache'
 
  const data = await fetch('/api/data')
  return data
}

交错

如果你需要将不可序列化的参数传递给可缓存函数,你可以将它们作为 children 传递。这意味着 children 引用可以改变而不影响缓存条目。

app/page.tsx
TypeScript
export default async function Page() {
  const uncachedData = await getData()
  return (
    <CacheComponent>
      <DynamicComponent data={uncachedData} />
    </CacheComponent>
  )
}
 
async function CacheComponent({ children }: { children: ReactNode }) {
  'use cache'
  const cachedData = await fetch('/api/cached-data')
  return (
    <div>
      <PrerenderedComponent data={cachedData} />
      {children}
    </div>
  )
}

你还可以通过缓存组件将服务器操作传递给客户端组件,而无需在可缓存函数内调用它们。

app/page.tsx
TypeScript
import ClientComponent from './ClientComponent'
 
export default async function Page() {
  const performUpdate = async () => {
    'use server'
    // 执行一些服务器端更新
    await db.update(...)
  }
 
  return <CacheComponent performUpdate={performUpdate} />
}
 
async function CachedComponent({
  performUpdate,
}: {
  performUpdate: () => Promise<void>
}) {
  'use cache'
  // 不要在这里调用 performUpdate
  return <ClientComponent action={performUpdate} />
}
app/ClientComponent.tsx
TypeScript
'use client'
 
export default function ClientComponent({
  action,
}: {
  action: () => Promise<void>
}) {
  return <button onClick={action}>Update</button>
}

平台支持

部署选项支持情况
Node.js 服务器
Docker 容器
静态导出
适配器平台特定

了解如何在自托管 Next.js 时配置缓存

版本历史

版本变更
v15.0.0"use cache" 作为实验性功能引入。