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

如何在Apollo Client Mutation后将实体添加到匹配查询变量的缓存中?

Apollo缓存更新:多变量查询场景的精细处理

针对你遇到的mutation后需更新多组变量查询缓存的问题,以下是几种实用的精细解决方案:

1. 利用字段政策(Field Policies)统一处理缓存逻辑

这是最符合Apollo缓存设计理念的方案,通过定义字段的读取和合并规则,让缓存自动识别哪些列表应包含新条目。

在创建Apollo Client时,为返回工时列表的字段配置自定义政策:

const client = new ApolloClient({
  uri: '/graphql',
  cache: new InMemoryCache({
    typePolicies: {
      Query: {
        fields: {
          timeEntries: {
            // 读取缓存时自动过滤符合当前查询变量的条目
            read(existing = [], { args }) {
              return existing.filter(entry => 
                entry.projectId === args.projectId &&
                entry.startDate >= args.startDate &&
                entry.endDate <= args.endDate
              );
            },
            // 新增条目时直接写入根缓存,后续由read逻辑分发到对应查询
            merge(existing = [], incoming) {
              // 去重避免重复添加
              const existingIds = new Set(existing.map(e => e.id));
              return [...existing, ...incoming.filter(e => !existingIds.has(e.id))];
            }
          }
        }
      }
    }
  })
});

mutation成功后,只需将新条目写入缓存根节点,无需关心具体查询变量:

const ADD_TIME_ENTRY = gql`
  mutation AddTimeEntry($input: TimeEntryInput!) {
    addTimeEntry(input: $input) {
      id
      projectId
      startDate
      endDate
      // 其他字段
    }
  }
`;

// 执行mutation时的update函数
update(cache, { data: { addTimeEntry } }) {
  cache.writeFragment({
    fragment: gql`
      fragment NewTimeEntry on TimeEntry {
        id
        projectId
        startDate
        endDate
      }
    `,
    data: addTimeEntry,
    // 将条目写入Query.timeEntries的根缓存
    id: cache.identify({ __typename: 'Query', timeEntries: [] })
  });
}

后续任何查询timeEntries的请求,都会通过read函数自动过滤出符合变量条件的条目,包括之前使用过的变量组合。

2. 遍历缓存查询,手动更新符合条件的缓存

如果无法使用字段政策,可以直接解析缓存中的查询键,找出所有匹配新条目的查询并更新:

// mutation的update函数
update(cache, { data: { addTimeEntry } }) {
  const rootQuery = cache.extract().ROOT_QUERY;
  const targetQueryName = 'timeEntries';

  Object.keys(rootQuery).forEach(queryKey => {
    // 匹配以目标查询名称开头的缓存键
    if (!queryKey.startsWith(`${targetQueryName}(`)) return;

    try {
      // 解析查询变量(注意:Apollo缓存的变量字符串格式可能需调整解析逻辑)
      const varStr = queryKey.slice(targetQueryName.length + 1, -1);
      // 替换Apollo生成的变量格式为标准JSON
      const formattedVarStr = varStr.replace(/([a-zA-Z0-9_]+):/g, '"$1":');
      const variables = JSON.parse(formattedVarStr);

      // 判断新条目是否符合当前查询的筛选条件
      const isMatch = 
        addTimeEntry.projectId === variables.projectId &&
        addTimeEntry.startDate >= variables.startDate &&
        addTimeEntry.endDate <= variables.endDate;

      if (isMatch) {
        // 读取当前查询的缓存数据并追加新条目
        const existingData = cache.readQuery({
          query: TIME_ENTRIES_QUERY,
          variables
        });
        cache.writeQuery({
          query: TIME_ENTRIES_QUERY,
          variables,
          data: {
            timeEntries: [...existingData.timeEntries, addTimeEntry]
          }
        });
      }
    } catch (e) {
      // 解析失败则跳过该查询
      return;
    }
  });
}

3. 优化refetchQueries,只刷新符合条件的查询

若你倾向于使用refetch而非手动更新缓存,可以缩小刷新范围,只重新获取包含新条目的查询:

// mutation配置中的refetchQueries
refetchQueries: async ({ cache, data }) => {
  const newEntry = data.addTimeEntry;
  const rootQuery = cache.extract().ROOT_QUERY;
  const relevantQueries = [];

  Object.keys(rootQuery).forEach(queryKey => {
    if (!queryKey.startsWith('timeEntries(')) return;

    try {
      const varStr = queryKey.slice('timeEntries('.length, -1);
      const formattedVarStr = varStr.replace(/([a-zA-Z0-9_]+):/g, '"$1":');
      const variables = JSON.parse(formattedVarStr);

      if (
        newEntry.projectId === variables.projectId &&
        newEntry.startDate >= variables.startDate &&
        newEntry.endDate <= variables.endDate
      ) {
        relevantQueries.push({
          query: TIME_ENTRIES_QUERY,
          variables
        });
      }
    } catch (e) {}
  });

  return relevantQueries;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 04:07:25