useMemo依赖Apollo useQuery返回的data变更时未触发执行问题排查
问题根本原因
- Apollo Client 的
useQuery返回的data是全局共享缓存数据的直接引用,没有做额外拷贝,以此降低性能开销。 - 你在第一个标签页的
useMemo逻辑里直接修改了data对象,相当于直接篡改了 Apollo 全局缓存中的存储值。 - 第二个标签页的组件请求新数据时,若 Apollo 对比新返回的接口数据与缓存中已被篡改的数据后,判断无需更新引用,就会返回和上一次渲染完全相同的
data引用。 - 原生
useMemo对依赖项做的是浅比较,只要引用地址不变,哪怕对象内部属性已经发生变化,也不会重新执行内部逻辑。
修复方案
- 禁止直接修改
useQuery返回的data原对象
所有对data的修改都要基于副本操作,不要改动原对象:
const result = useMemo(() => { // 浅结构用扩展运算符拷贝,深层结构可以用 structuredClone 或业务适配的深拷贝逻辑 const dataCopy = {...data}; // 所有修改操作都针对 dataCopy 执行 // 你的业务逻辑 }, [data])
- 调整
useQuery配置强制返回新对象引用
如果需要规避缓存复用的问题,可以给useQuery配置独立的请求策略,确保每次请求返回新的对象引用:
const { data, loading, error: loadRolesError } = useQuery(你的查询语句, { fetchPolicy: 'network-only', nextFetchPolicy: 'network-only' });
- 拆分
useMemo依赖项
如果业务需要感知data内部特定属性的变化,可以把关键属性提取出来作为依赖,代替直接用整个data对象:
const result = useMemo(() => { // 业务逻辑 }, [data?.id, data?.列表字段?.length, loading])
- 使用深比较的自定义缓存Hook
如果必须监听对象所有深层属性的变化,可以自行实现基于深比较的useDeepMemo代替原生useMemo,注意评估深比较带来的性能开销。
内容的提问来源于stack exchange,提问作者Nadish Sood
相关产品推荐
相关产品推荐

