cache 允许缓存数据获取或计算的结果。
const cachedFn = cache(fn);参考
cache(fn)
在任何组件之外调用 cache 以创建带有缓存的函数版本。
import {cache} from 'react';
import calculateMetrics from 'lib/metrics';
const getMetrics = cache(calculateMetrics);
function Chart({data}) {
const report = getMetrics(data);
// ...
}当首次使用 data 调用 getMetrics 时,getMetrics 将调用 calculateMetrics(data) 并将结果存储在缓存中。如果再次使用相同的 data 调用 getMetrics,它将返回缓存的结果,而不会再次调用 calculateMetrics(data)。
参数
fn:要对其结果进行缓存的函数。fn可以接受任何参数并返回任何值。
返回值
cache 返回一个与 fn 具有相同类型签名的已缓存版本。在此过程中,它不会调用 fn。
在使用给定的参数调用 cachedFn 时,它首先检查缓存中是否存在缓存的结果。如果存在缓存的结果,它将返回该结果。如果没有,它将使用参数调用 fn,将结果存储在缓存中,并返回该结果。只有在缓存未命中时才会调用 fn。
注意
- React 将在每次服务器请求时使所有记忆化函数的缓存失效。
- 每次调用
cache都会创建一个新函数。这意味着多次使用相同的函数调用cache将返回不共享相同缓存的不同记忆化函数。 cachedFn还会缓存错误。如果对于某些参数fn抛出错误,错误将被缓存,当使用相同参数调用cachedFn时,相同的错误将被重新抛出。cache仅供在 服务器组件 中使用。
用法
缓存代价昂贵的计算
使用 cache 跳过重复工作。
import {cache} from 'react';
import calculateUserMetrics from 'lib/user';
const getUserMetrics = cache(calculateUserMetrics);
function Profile({user}) {
const metrics = getUserMetrics(user);
// ...
}
function TeamReport({users}) {
for (let user in users) {
const metrics = getUserMetrics(user);
// ...
}
// ...
}如果相同的 user 对象在 Profile 和 TeamReport 中都被渲染,那么这两个组件可以共享工作,并且只为该 user 调用一次 calculateUserMetrics。
假设首先渲染了 Profile。它将调用 getUserMetrics,并检查是否有缓存的结果。由于这是第一次以该 user 调用 getUserMetrics,所以缓存未命中。于是 getUserMetrics 将会使用 user 调用 calculateUserMetrics 并将结果写入缓存。
当 TeamReport 使用相同的 user 对象来渲染 users 列表时,它将调用 getUserMetrics 并从缓存中读取结果。
如果可以通过传递 AbortSignal 来中止 calculateUserMetrics,则可以使用 cacheSignal(),以便在 React 完成渲染后取消昂贵的计算。calculateUserMetrics 可以直接使用 cacheSignal 在内部处理取消。
共享数据快照
要在组件之间共享数据快照,请使用类似 fetch 的数据获取函数调用 cache。当多个组件进行相同的数据获取时,只会发出一个请求,并且返回的数据会被缓存并在各个组件之间共享。所有组件在服务器渲染期间都引用相同的数据快照。
import {cache} from 'react';
import {fetchTemperature} from './api.js';
const getTemperature = cache(async (city) => {
return await fetchTemperature(city);
});
async function AnimatedWeatherCard({city}) {
const temperature = await getTemperature(city);
// ...
}
async function MinimalWeatherCard({city}) {
const temperature = await getTemperature(city);
// ...
}如果 AnimatedWeatherCard 和 MinimalWeatherCard 都为相同的 city 进行渲染,它们将从 记忆化函数 接收相同的数据快照。
如果 AnimatedWeatherCard 和 MinimalWeatherCard 向 getTemperature 提供不同的 city 参数,那么将调用两次 fetchTemperature,并且每个调用站点将接收不同的数据。
city 在其中充当缓存键。
预加载数据
通过缓存长时间运行的数据获取,你可以在渲染组件之前开始异步工作。
const getUser = cache(async (id) => {
return await db.user.query(id);
});
async function Profile({id}) {
const user = await getUser(id);
return (
<section>
<img src={user.profilePic} />
<h2>{user.name}</h2>
</section>
);
}
function Page({id}) {
// ✅ 正确示例:开始获取用户数据。
getUser(id);
// ……一些计算工作
return (
<>
<Profile id={id} />
</>
);
}在渲染 Page 时,组件调用 getUser,但请注意它并不使用返回的数据。这个早期的