Apollo Client执行evict移除缓存后组件未重新渲染问题
原因分析
你调用evict仅删除了缓存中独立的Address类型对象,但持有该对象引用的父级查询缓存(比如地址列表查询、当前用户关联地址字段的缓存)并未同步更新。Apollo Client的组件重渲染触发逻辑是监听组件所使用的查询结果的变更,只要父查询的返回数据没有发生变化,即使引用的子对象被删除,组件也不会感知到缓存变动,因此不会触发重渲染。
解决方案
- 方案1:同步修改父级查询缓存(最推荐)
在evict删除对象后,调用cache.modify更新持有该地址引用的父级字段,移除对应引用。示例代码如下:
deleteAddress({ variables: { id: data.address.id }, update: (cache) => { const targetAddressId = cache.identify(data.address); // 先删除Address对象 cache.evict({ id: targetAddressId }); // 修改ROOT_QUERY下的地址列表字段,移除被删除的地址引用 cache.modify({ fields: { // 这里替换为你实际查询地址列表的字段名,比如getUserAddresses、addresses等 addresses(existingAddressRefs = [], { readField }) { return existingAddressRefs.filter( addressRef => readField('id', addressRef) !== data.address.id ); } } }); cache.gc(); }, })
如果地址列表是嵌套在其他对象下的字段(比如当前登录用户的地址列表),需要在cache.modify中指定父对象的id:
cache.modify({ id: cache.identify(currentUser), // 替换为持有地址列表的父对象实例 fields: { addresses(existingAddressRefs = [], { readField }) { return existingAddressRefs.filter( addressRef => readField('id', addressRef) !== data.address.id ); } } });
这种方式直接修改组件依赖的父查询结果,会自动触发关联组件的重渲染,无需额外配置。
- 方案2:给evict配置广播参数
如果你的场景是组件直接查询单个Address对象而非通过列表引用,可以在调用evict时添加broadcast: true参数,强制广播缓存变更通知所有订阅该对象的组件:
cache.evict({ id: cache.identify(data.address), broadcast: true });
- 方案3:检查组件查询配置
确认组件使用的useQuery没有配置fetchPolicy: 'cache-only'且关闭了订阅,默认的cache-first策略是可以感知缓存变更的,如果配置了不监听缓存的策略也会导致不重渲染。
内容的提问来源于stack exchange,提问作者Kittichote Chain
相关产品推荐
相关产品推荐

