Files
2026-07-13 21:36:17 +08:00

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 文档