Vue3组合式API中GraphQL删除Mutation后更新Apollo缓存问题
Vue3组合式API中GraphQL删除Mutation后更新缓存的正确姿势
在Vue3组合式API项目中,使用Apollo Client执行删除Mutation后,尝试多种方式更新查询缓存均失败,以下是项目配置、问题分析及解决方案:
项目配置回顾
1. Vue与Apollo Client配置(main.js)
import { createApp, provide, h } from "vue" import App from "./App.vue" import router from "./router"; import { InMemoryCache, HttpLink, ApolloClient } from "@apollo/client"; import { DefaultApolloClient } from '@vue/apollo-composable'; const apClient = new ApolloClient({ cache: new InMemoryCache({ addTypename: false }), // 注意此处关闭了自动添加__typename link: new HttpLink({ uri: 'http://localhost:8000/graphql' }), }); const app =createApp({ setup() { provide(DefaultApolloClient, apClient); }, render: () => h(App), }); app.use(router) .mount('#app')
2. GraphQL查询与Mutation
查询语句(getMatters)
query getMatters($id:ID, $client:ID) { Matters(client:$client, id:$id) { client { id name } category id title status } }
删除Mutation(deleteMatter)
mutation deleteMatter($input:[MatterUpdate] ){ DeleteMatter(input: $input) { success errors } }
现有方法的问题分析
方法一:cache.evict + cache.gc失效
关闭addTypename: false后,Apollo无法自动为缓存对象添加__typename字段,而cache.identify()需要依赖__typename+id生成唯一缓存键,导致evict无法定位目标缓存项,因此失效。
方法二:读取修改缓存时报错data.matters is undefined
查询返回的字段是大写M的Matters,但代码中误用了小写data.matters,字段名不匹配导致读取不到数据。
方法三:splice修改缓存数组报错
Apollo Client的缓存数据是不可变的,直接用splice修改原数组会触发不可变约束的报错,必须创建新数组更新缓存。
正确解决方案
方案1:开启addTypename后使用cache.modify(推荐)
首先修改Apollo缓存配置,开启自动添加__typename(Apollo默认行为,不建议关闭):
const apClient = new ApolloClient({ cache: new InMemoryCache(), // 移除addTypename: false,默认开启 link: new HttpLink({ uri: 'http://localhost:8000/graphql' }), });
然后在useMutation中使用cache.modify直接更新查询缓存,无需手动读取整个查询:
const { mutate: deleteResult } = useMutation(deleteMatter, { variables: { input: { id: matter.value.id } }, update: (cache) => { // 修改getMatters查询的缓存数据 cache.modify({ fields: { Matters(existingMatters = [], { readField }) { // 过滤已删除项,返回新数组 return existingMatters.filter(item => readField('id', item) !== matter.value.id); } } }); } });
方案2:手动读取并写入缓存(适配关闭addTypename的场景)
若必须关闭addTypename,可通过以下方式正确更新缓存:
const { mutate: deleteResult } = useMutation(deleteMatter, { variables: { input: { id: matter.value.id } }, update: (cache) => { // 读取当前查询的缓存数据,注意字段名是Matters(大写M) const existingData = cache.readQuery({ query: getMatters, variables: { client: id.value } // 确保变量与查询时完全一致 }); if (!existingData?.Matters) return; // 创建新数组,过滤删除项 const updatedMatters = existingData.Matters.filter(item => item.id !== matter.value.id); // 写入更新后的缓存,字段名与查询一致(Matters) cache.writeQuery({ query: getMatters, variables: { client: id.value }, data: { Matters: updatedMatters } }); } });
关键注意事项
- 变量一致性:调用
readQuery和writeQuery时,变量必须与当初执行查询时完全相同,否则无法匹配对应缓存项。 - 缓存不可变:永远不要直接修改Apollo返回的缓存数据,必须通过创建新对象/数组的方式更新。
- __typename作用:建议开启自动添加
__typename,这是Apollo缓存正常工作的基础,可避免大量缓存定位问题。
内容的提问来源于stack exchange,提问作者ccsv
相关产品推荐
相关产品推荐

