2.2 KiB
2.2 KiB
title, impact, impactDescription, tags
| title | impact | impactDescription | tags |
|---|---|---|---|
| Per-Request Deduplication with React.cache() | MEDIUM | deduplicates within request | server, cache, react-cache, deduplication |
使用 React.cache() 实现单次请求内的去重
使用 React.cache() 实现服务端请求去重。身份验证和数据库查询受益最大。
用法:
import { cache } from 'react'
export const getCurrentUser = cache(async () => {
const session = await auth()
if (!session?.user?.id) return null
return await db.user.findUnique({
where: { id: session.user.id }
})
})
在单次请求中,多次调用 getCurrentUser() 仅执行一次查询。
避免使用内联对象作为参数:
React.cache() 使用浅相等(Object.is)来判断缓存是否命中。内联对象每次调用都会创建新的引用,导致无法命中缓存。
错误做法(总是缓存未命中):
const getUser = cache(async (params: { uid: number }) => {
return await db.user.findUnique({ where: { id: params.uid } })
})
// 每次调用都创建新对象,永远不会命中缓存
getUser({ uid: 1 })
getUser({ uid: 1 }) // 缓存未命中,再次执行查询
正确做法(缓存命中):
const getUser = cache(async (uid: number) => {
return await db.user.findUnique({ where: { id: uid } })
})
// 原始类型参数使用值相等判断
getUser(1)
getUser(1) // 缓存命中,返回缓存结果
如果必须传递对象,请传递同一个引用:
const params = { uid: 1 }
getUser(params) // 执行查询
getUser(params) // 缓存命中(同一引用)
Next.js 特别说明:
在 Next.js 中,fetch API 已自动扩展了请求记忆化功能。相同 URL 和选项的请求在单次请求内会自动去重,因此 fetch 调用无需使用 React.cache()。但 React.cache() 对其他异步任务仍然至关重要:
- 数据库查询(Prisma、Drizzle 等)
- 大量计算
- 身份验证检查
- 文件系统操作
- 任何非
fetch的异步工作
使用 React.cache() 在组件树中对这些操作进行去重。
参考文档:React.cache 文档