主题
使用缓存
¥use cache
use cache
指令允许你将路由、React 组件或函数标记为可缓存。它可以用在文件顶部,以指示文件中的所有导出都应该被缓存,或者内联在函数或组件的顶部以缓存返回值。
¥The use cache
directive allows you to mark a route, React component, or a function as cacheable. It can be used at the top of a file to indicate that all exports in the file should be cached, or inline at the top of function or component to cache the return value.
用法
¥Usage
use cache
目前是一个实验性功能。要启用此功能,请在 next.config.ts
文件中添加 useCache
选项:
¥use cache
is currently an experimental feature. To enable it, add the useCache
option to your next.config.ts
file:
ts
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
useCache: true,
},
}
export default nextConfig
js
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
useCache: true,
},
}
module.exports = nextConfig
需要了解:
use cache
也可以通过dynamicIO
选项启用。¥Good to know:
use cache
can also be enabled with thedynamicIO
option.
然后,在文件、组件或函数级别添加 use cache
:
¥Then, add use cache
at the file, component, or function level:
tsx
// File level
'use cache'
export default async function Page() {
// ...
}
// Component level
export async function MyComponent() {
'use cache'
return <></>
}
// Function level
export async function getData() {
'use cache'
const data = await fetch('/api/data')
return data
}
use cache
的工作原理
¥How use cache
works
缓存键
¥Cache keys
缓存条目的键是使用其输入的序列化版本生成的,其中包括:
¥A cache entry's key is generated using a serialized version of its inputs, which includes:
构建 ID(每次构建都会生成)
¥Build ID (generated for each build)
函数 ID(函数的唯一安全标识符)
¥Function ID (a secure identifier unique to the function)
serializable 函数参数(或 props)。
¥The serializable function arguments (or props).
传递给缓存函数的参数以及它从父作用域读取的任何值都会自动成为键的一部分。这意味着,只要输入相同,相同的缓存条目就会被重用。
¥The arguments passed to the cached function, as well as any values it reads from the parent scope automatically become a part of the key. This means, the same cache entry will be reused as long as its inputs are the same.
不可序列化参数
¥Non-serializable arguments
任何不可序列化的参数、props 或封闭值将在缓存函数内转换为引用,并且只能传递,而不能检查或修改。这些不可序列化的值将在请求时填写,不会成为缓存键的一部分。
¥Any non-serializable arguments, props, or closed-over values will turn into references inside the cached function, and can be only passed through and not inspected nor modified. These non-serializable values will be filled in at the request time and won't become a part of the cache key.
例如,缓存函数可以将 JSX 作为 children
prop 接收并返回 <div>{children}</div>
,但它无法自省实际的 children
对象。这允许你将未缓存的内容嵌套在已缓存的组件中。
¥For example, a cached function can take in JSX as a children
prop and return <div>{children}</div>
, but it won't be able to introspect the actual children
object. This allows you to nest uncached content inside a cached component.
tsx
function CachedComponent({ children }: { children: ReactNode }) {
'use cache'
return <div>{children}</div>
}
jsx
function CachedComponent({ children }) {
'use cache'
return <div>{children}</div>
}
返回值
¥Return values
可缓存函数的返回值必须是可序列化的。这可确保缓存的数据可以正确存储和检索。
¥The return value of the cacheable function must be serializable. This ensures that the cached data can be stored and retrieved correctly.
构建时 use cache
¥use cache
at build time
当在 layout 或 page 的顶部使用时,路由段将被预渲染,以便稍后将其转换为 revalidated。
¥When used at the top of a layout or page, the route segment will be prerendered, allowing it to later be revalidated.
这意味着 use cache
不能像 cookies
或 headers
那样与 请求时 API 一起使用。
¥This means use cache
cannot be used with request-time APIs like cookies
or headers
.
运行时 use cache
¥use cache
at runtime
在服务器上,各个组件或函数的缓存条目将缓存在内存中。
¥On the server, the cache entries of individual components or functions will be cached in-memory.
然后,在客户端,从服务器缓存返回的任何内容都将在会话期间或直到 revalidated 之前存储在浏览器内存中。
¥Then, on the client, any content returned from the server cache will be stored in the browser's memory for the duration of the session or until revalidated.
在重新验证期间
¥During revalidation
默认情况下,use cache
的服务器端重新验证期为 15 分钟。虽然这个时间段对于不需要频繁更新的内容可能有用,但你可以使用 cacheLife
和 cacheTag
API 来配置何时重新验证各个缓存条目。
¥By default, use cache
has server-side revalidation period of 15 minutes. While this period may be useful for content that doesn't require frequent updates, you can use the cacheLife
and cacheTag
APIs to configure when the individual cache entries should be revalidated.
cacheLife
:配置缓存条目的生命周期。¥
cacheLife
: Configure the cache entry lifetime.cacheTag
:创建标签以进行按需重新验证。¥
cacheTag
: Create tags for on-demand revalidation.
这两个 API 都集成在客户端和服务器缓存层中,这意味着你可以在一个地方配置缓存语义并让它们应用于任何地方。
¥Both of these APIs integrate across the client and server caching layers, meaning you can configure your caching semantics in one place and have them apply everywhere.
有关更多信息,请参阅 cacheLife
和 cacheTag
API 文档。
¥See the cacheLife
and cacheTag
API docs for more information.
示例
¥Examples
使用 use cache
缓存整个路由
¥Caching an entire route with use cache
要预渲染整个路由,请将 use cache
添加到 layout
和 page
文件的顶部。这些段中的每一个都被视为应用中的单独入口点,并将被独立缓存。
¥To prerender an entire route, add use cache
to the top of both the layout
and page
files. Each of these segments are treated as separate entry points in your application, and will be cached independently.
tsx
'use cache'
export default function Layout({ children }: { children: ReactNode }) {
return <div>{children}</div>
}
jsx
'use cache'
export default function Layout({ children }) {
return <div>{children}</div>
}
导入并嵌套在 page
文件中的任何组件都将继承 page
的缓存行为。
¥Any components imported and nested in page
file will inherit the cache behavior of page
.
tsx
'use cache'
async function Users() {
const users = await fetch('/api/users')
// loop through users
}
export default function Page() {
return (
<main>
<Users />
</main>
)
}
jsx
'use cache'
async function Users() {
const users = await fetch('/api/users')
// loop through users
}
export default function Page() {
return (
<main>
<Users />
</main>
)
}
需要了解:
¥Good to know:
如果仅将
use cache
添加到layout
或page
,则只有该路由段及其导入的任何组件才会被缓存。¥If
use cache
is added only to thelayout
or thepage
, only that route segment and any components imported into it will be cached.如果路由中任何嵌套子项使用 动态 API,则该路由将选择退出预渲染。
¥If any of the nested children in the route use Dynamic APIs, then the route will opt out of prerendering.
使用 use cache
缓存组件输出
¥Caching a component's output with use cache
你可以在组件级别使用 use cache
来缓存在该组件内执行的任何提取或计算。只要序列化的 props 在每个实例中产生相同的值,缓存条目就会被重用。
¥You can use use cache
at the component level to cache any fetches or computations performed within that component. The cache entry will be reused as long as the serialized props produce the same value in each instance.
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
}
jsx
export async function Bookings({ type = 'haircut' }) {
'use cache'
async function getBookingsData() {
const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)
return data
}
return //...
}
使用 use cache
缓存函数输出
¥Caching function output with use cache
由于你可以将 use cache
添加到任何异步函数,因此你不仅限于缓存组件或路由。你可能需要缓存网络请求、数据库查询或慢速计算。
¥Since you can add use cache
to any asynchronous function, you aren't limited to caching components or routes only. You might want to cache a network request, a database query, or a slow computation.
tsx
export async function getData() {
'use cache'
const data = await fetch('/api/data')
return data
}
jsx
export async function getData() {
'use cache'
const data = await fetch('/api/data')
return data
}
交错
¥Interleaving
如果你需要将不可序列化的参数传递给可缓存函数,则可以将它们作为 children
传递。这意味着 children
引用可以更改而不会影响缓存条目。
¥If you need to pass non-serializable arguments to a cacheable function, you can pass them as children
. This means the children
reference can change without affecting the cache entry.
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>
)
}
jsx
export default async function Page() {
const uncachedData = await getData()
return (
<CacheComponent>
<DynamicComponent data={uncachedData} />
</CacheComponent>
)
}
async function CacheComponent({ children }) {
'use cache'
const cachedData = await fetch('/api/cached-data')
return (
<div>
<PrerenderedComponent data={cachedData} />
{children}
</div>
)
}
你也可以通过缓存的组件将服务器操作传递给客户端组件,而无需在可缓存函数内调用它们。
¥You can also pass Server Actions through cached components to Client Components without invoking them inside the cacheable function.
tsx
import ClientComponent from './ClientComponent'
export default async function Page() {
const performUpdate = async () => {
'use server'
// Perform some server-side update
await db.update(...)
}
return <CacheComponent performUpdate={performUpdate} />
}
async function CachedComponent({
performUpdate,
}: {
performUpdate: () => Promise<void>
}) {
'use cache'
// Do not call performUpdate here
return <ClientComponent action={performUpdate} />
}
jsx
import ClientComponent from './ClientComponent'
export default async function Page() {
const performUpdate = async () => {
'use server'
// Perform some server-side update
await db.update(...)
}
return <CacheComponent performUpdate={performUpdate} />
}
async function CachedComponent({ performUpdate }) {
'use cache'
// Do not call performUpdate here
return <ClientComponent action={performUpdate} />
}
tsx
'use client'
export default function ClientComponent({
action,
}: {
action: () => Promise<void>
}) {
return <button onClick={action}>Update</button>
}
jsx
'use client'
export default function ClientComponent({ action }) {
return <button onClick={action}>Update</button>
}