You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Apollo Client React Native缓存:所有查询/突变都需id/_id字段吗?

Apollo Client缓存规范化与无主键类型的常见问题解答

核心前提:Apollo缓存规范化的逻辑

Apollo Client的缓存规范化仅针对带有唯一标识字段(默认id/_id,可自定义)的类型生效:

  • 带主键的类型会被拆解为独立对象,存储在缓存的规范化存储区,所有引用该对象的查询结果都会指向这个唯一实例,避免重复存储,且能自动同步更新。
  • 不带主键的类型不会被规范化,会作为完整的查询结果条目存储,以「查询名称+变量组合」作为缓存键,无法被识别为同一类数据的不同实例。

针对你的场景的具体问题解答

1. 无id/_id的Rooms类型能否被正确规范化?

不能。Rooms类型没有主键字段,Apollo不会将其拆解到规范化存储区,只会把getChatRoomsForUser的整个查询结果作为独立缓存条目存储。

2. 每次查询是否会重复添加缓存而非更新?

分两种情况:

  • 如果getChatRoomsForUser没有查询变量(userId通过context获取,查询本身不接收参数):每次查询会直接覆盖之前的缓存条目,不会重复存储。
  • 如果后续为分页添加了page等变量:不同变量组合的查询会生成不同的缓存键,此时会生成多个独立的缓存条目,造成冗余存储,且这些条目不会自动合并更新。

3. 会影响突变的缓存自动更新吗?

会严重影响。以删除房间的突变为例:

  • 虽然Room类型有主键,Apollo能正确删除缓存中的Room对象,但getChatRoomsForUser返回的Rooms条目是独立存储的,Apollo无法识别这个条目里的rooms数组引用了被删除的Room,因此不会自动更新该数组。
  • 你必须手动编写update函数,找到getChatRoomsForUser的缓存条目,从rooms数组中移除对应的Room对象。

4. 若Rooms有id/_id,是否无需手动编写update/merge函数?

不一定,得结合场景:

  • 首先需要自定义dataIdFromObject函数,指定Rooms的主键(比如用关联的userId作为唯一标识,因为Rooms是某个用户的房间列表),让Apollo能规范化存储Rooms对象。
  • 对于简单的非分页列表:当Room被删除时,Apollo会自动更新Rooms对象中的rooms数组(因为数组元素是对规范化Room对象的引用)。
  • 对于分页列表:即使Rooms有主键,Apollo默认也不会自动更新不同分页的列表条目,此时仍需结合@connection指令定义列表的唯一标识,或手动编写update函数来同步分页数据。

5. 此类问题会在其他无主键的查询/突变中加剧吗?

是的,问题会更严重:

  • 所有无主键的类型,其缓存都以查询条目形式存储,无法共享或自动同步,导致缓存冗余。
  • 任何涉及这类类型的突变,都需要手动处理所有相关的缓存条目,维护成本会随着查询/突变数量增加而急剧上升。

优化建议

  • 给Rooms类型添加逻辑主键(比如userId),并通过dataIdFromObject配置告诉Apollo使用该字段作为唯一标识。
  • 对于分页列表,使用@connection指令定义列表的唯一名称,让Apollo能自动合并不同分页的缓存数据。
  • 复杂场景下,优先依赖规范化缓存的自动更新能力,减少手动update函数的编写。

内容的提问来源于stack exchange,提问作者Matt Volonnino

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 00:06:26