服务端缓存与取消
cache 在服务端组件中缓存什么?
- 函数包装:
cache(fn)返回记忆化函数,相同参数的调用可以共享计算结果或同一个异步 Promise; - 请求范围: React 在不同服务端请求之间失效缓存,它不是跨用户、跨请求的永久数据库缓存;
- 声明复用: 在模块层创建并导出同一个包装函数,多次调用 cache(fn) 会产生互不共享的缓存;
import { cache } from "react";
export const getUser = cache(async (id) => {
return database.users.find(id);
});
async function Profile({ id }) {
const user = await getUser(id);
return <h1>{user.name}</h1>;
}
为什么看似相同参数没有命中缓存?
- 参数身份: 参数逐项按 Object.is 比较,每次新建的对象不是同一个参数,优先传稳定 ID 等原始值;
- 调用上下文: 缓存能力依赖服务端 React 渲染上下文,在外部普通代码中调用无法使用缓存;
- 错误结果: 同组参数对应的抛错也会被缓存,不能假定再次调用必然重新尝试请求;
如何提前启动同一份服务端数据请求?
- 预加载: 在确定将需要数据时先调用缓存函数启动工作,之后在消费组件 await 同一参数;
const getUser = cache(async (id) => {
return await db.user.query(id);
});
async function Profile({ id }) {
const user = await getUser(id);
// ...
}
function Page({ id }) {
getUser(id);
return <Profile id={id} />;
}
cacheSignal 如何终止不再需要的工作?
- 当前仅用于服务器组件;
- 生命周期: 在服务端渲染中调用 cacheSignal 得到 AbortSignal,渲染完成、失败或中止后取消不再需要的进行中工作;
- 空值情况: 渲染外和当前 Client Component 环境返回 null,不适用 cache 的生命周期;
import { cache, cacheSignal } from "react";
const load = cache(async (url) => {
const response = await fetch(url, { signal: cacheSignal() });
if (!response.ok) throw new Error("请求失败");
return response.json();
});