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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 05:36:07