跳到主要内容

use cache

use cache 指令允许你将某个路由、React 组件或函数标记为可缓存。你可以在文件顶部添加该指令,表示该文件中所有导出的内容都将被缓存;也可以在组件或函数顶部内联使用,实现对返回值的缓存。

用法

use cache 目前属于实验性特性。要启用它,请在 next.config.ts 文件中添加 useCache 选项:

next.config.ts
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
experimental: {
useCache: true,
},
}

export default nextConfig

提示: 你也可以通过 dynamicIO 选项启用 use cache

然后,在文件、组件或函数级别添加 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 的工作原理

缓存键

缓存条目的 key 是通过对其输入进行序列化生成的,主要包括:

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

传递给被缓存函数的参数,以及它从父作用域读取的任何值,都会自动成为缓存 key 的一部分。也就是说,只要输入相同,就会复用同一个缓存条目。

非可序列化参数

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

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

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

返回值

可缓存函数的返回值必须是可序列化的。这样才能确保缓存数据能够被正确存储和读取。

构建时的 use cache

当你在 layoutpage 文件顶部使用 use cache 时,该路由段会被预渲染,从而支持后续的再验证

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

运行时的 use cache

服务端,各个组件或函数的缓存条目会存储在内存中。

客户端,从服务端缓存返回的内容会存储在浏览器内存中,持续到会话结束或被再验证

再验证期间

默认情况下,use cache 的服务端再验证周期为 15 分钟。如果你的内容不需要频繁更新,这个周期可能已经足够。你也可以通过 cacheLifecacheTag API 配置每个缓存条目的再验证时机。

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

这两个 API 会在客户端和服务端缓存层之间协同工作,你可以在一个地方配置缓存策略,并在全局生效。

更多信息请参阅 cacheLifecacheTag 的 API 文档。

示例

使用 use cache 缓存整个路由

要预渲染整个路由,需要在 layoutpage 文件顶部都添加 use cache。每个路由段都会作为应用的独立入口被单独缓存。

app/layout.tsx
'use cache'

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

export default function Layout({ children }) {
return <div>{children}</div>
}

page 文件中导入和嵌套的所有组件都会继承 page 的缓存行为。

app/page.tsx
'use cache'

async function Users() {
const users = await fetch('/api/users')
// 遍历用户列表
}

export default function Page() {
return (
<main>
<Users />
</main>
)
}

提示:

  • 如果只在 layoutpage 文件中添加 use cache,则只有该路由段及其导入的组件会被缓存。
  • 如果路由中的任何嵌套子组件使用了 动态 API,该路由将不会被预渲染。

使用 use cache 缓存组件输出

你可以在组件级别使用 use cache,缓存该组件内部的 fetch 或计算操作。只要序列化后的 props 保持一致,缓存条目就会被复用。

app/components/bookings.tsx
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
export async function getData() {
'use cache'

const data = await fetch('/api/data')
return data
}

交错(Interleaving)

如果你需要向可缓存函数传递不可序列化的参数,可以通过 children 传递。这样,children 的引用变化不会影响缓存条目。

app/page.tsx
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>
)
}

你还可以通过缓存组件将 Server Actions 传递给客户端组件,而无需在可缓存函数内部调用它们。

app/page.tsx
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
'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" 作为实验性特性引入。