GraphQL中定义自定义合并函数解决InMemoryCache缓存数据丢失警告问题
解决Apollo Client缓存合并警告:Query.parts字段的自定义merge配置问题
首先得明确警告的核心原因:你之前把merge函数配置在了Part类型上,但警告明确指出是Query对象的parts字段需要自定义merge策略,这就是之前配置没生效的关键问题。
第一步:修正InMemoryCache的typePolicies配置
Apollo Client的缓存合并策略是针对具体字段的,这里需要给Query类型下的parts字段指定merge函数,而不是Part类型本身。修改你的缓存配置如下:
export const client = new ApolloClient({ link, cache: new InMemoryCache({ typePolicies: { // 针对Query类型配置字段级合并规则 Query: { fields: { // 为parts字段定义自定义merge逻辑 parts: { merge(existing = [], incoming = []) { // 适合删除场景:直接用新数据覆盖旧缓存数组 return incoming; // 若需要支持新增/更新的合并去重,可替换为: // const existingRefs = new Set(existing.map(item => item.__ref)); // return [...existing, ...incoming.filter(item => !existingRefs.has(item.__ref))]; } } } } } }) });
这个配置会告诉Apollo Client,处理Query.parts字段的缓存合并时,直接使用新的incoming数组替换旧数据(或按需合并),彻底消除缓存数据可能丢失的警告。
第二步:修正Mutation的update函数逻辑
你的update函数里存在缓存操作的小问题,导致evict未生效,加重了缓存合并冲突:
const [partDelete] = useMutation(DELETE_PART, { update(cache, { data }) { // 从mutation返回数据中提取被删除的Part(假设返回结构为{ deletePart: { part: { id: "xxx" } } }) const deletedPart = data.deletePart.part; // 生成正确的Part缓存ID const partCacheId = cache.identify({ __typename: "Part", id: deletedPart.id }); // 移除对应Part的缓存条目 cache.evict({ id: partCacheId }); // 手动更新Query.parts的缓存:过滤掉被删除的Part引用 const { parts } = cache.readQuery({ query: GET_PARTS }); const updatedParts = parts.filter(partRef => partRef.__ref !== partCacheId); cache.writeQuery({ query: GET_PARTS, data: { parts: updatedParts } }); }, // 手动更新缓存后可移除refetchQueries,避免重复请求 // refetchQueries: [{ query: GET_PARTS }] })
修改点说明:
- 直接从返回数据中提取被删除Part的ID,避免之前数组map导致的
refined.id为undefined的问题 - 用
cache.identify生成准确的缓存ID,确保evict操作能精准移除目标缓存 - 手动更新
parts缓存数组,让缓存数据与实际后端数据保持一致,减少合并冲突
完成这两步后,既能解决缓存合并警告,也能让缓存更新逻辑更准确可靠。
内容的提问来源于stack exchange,提问作者fedjedmedjed
相关产品推荐
相关产品推荐

