You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Apollo GraphQL中如何使分页、可排序筛选列表查询的所有缓存条目失效?

Apollo GraphQL中如何使分页、可排序筛选列表查询的所有缓存条目失效?

我完全懂你的困扰——Apollo Client会把每个不同排序、筛选组合的getItems查询结果单独缓存,新增条目后要让所有这些缓存同步更新确实有点棘手。你试过的refetchQueries只刷新默认参数的查询,no-cache又太激进,重置整个缓存更是没必要。下面给你几个更合适的解决方案,按实现复杂度和效率排序:

1. 最简单的方案:用invalidateQueries批量标记所有相关缓存失效

Apollo Client v3的invalidateQueries可以通过查询名称匹配所有对应的缓存条目,不管变量是什么。你只需要在mutation里配置这个选项,就能让所有getItems查询的缓存都被标记为“过时”,当依赖这些缓存的组件重新渲染时,会自动重新请求最新数据。

修改你的mutation代码:

createItemMutation({
  variables: {
    // 你的条目数据,比如title等
  },
  // 直接指定要失效的查询
  invalidateQueries: [{ query: getItems }],
})

如果你需要更精细的控制(比如只失效特定筛选类型的查询),还可以用过滤器函数:

invalidateQueries: {
  query: getItems,
  predicate: ({ variables }) => {
    // 示例:只失效包含"active"状态筛选的查询
    return variables.filters?.status === 'active';
  }
}

这个方案的优点是零额外逻辑,完全由Apollo处理失效和重新请求;缺点是会触发所有相关组件的重新请求,如果列表查询比较重,可能有轻微的性能影响,但大部分场景下完全可以接受。

2. 更高效的方案:手动更新所有匹配的缓存条目

如果不想触发额外的网络请求,你可以在mutation的update函数里遍历所有getItems的缓存条目,判断新创建的条目是否符合该条目的筛选、排序规则,然后直接更新缓存。这样用户能立刻看到新条目,不需要等网络请求。

示例代码:

createItemMutation({
  variables: {
    // 你的条目数据
  },
  update(cache, { data: { createItem } }) {
    // 找到所有getItems查询的缓存记录
    const allGetItemsEntries = cache.find({ query: getItems });

    allGetItemsEntries.forEach(({ query, variables }) => {
      // 读取当前缓存的列表数据
      const cachedData = cache.readQuery({ query, variables });
      if (!cachedData?.getItems) return;

      // 第一步:判断新条目是否符合当前查询的筛选条件
      const matchesFilters = checkItemAgainstFilters(createItem, variables.filters);
      if (!matchesFilters) return;

      // 第二步:根据当前查询的排序规则,把新条目插入到正确位置
      const updatedItems = insertIntoSortedList(
        [...cachedData.getItems.items],
        createItem,
        variables.sorting
      );

      // 第三步:写回缓存,记得更新totalCount(如果你的分页有这个字段)
      cache.writeQuery({
        query,
        variables,
        data: {
          getItems: {
            ...cachedData.getItems,
            items: updatedItems,
            totalCount: cachedData.getItems.totalCount + 1
          }
        }
      });
    });
  },
})

这里需要你自己实现两个辅助函数:

  • checkItemAgainstFilters:对照查询的筛选参数,判断新条目是否应该出现在这个列表里(逻辑要和后端保持一致)
  • insertIntoSortedList:根据查询的排序规则,把新条目插入到数组的正确位置(比如按title升序、创建时间降序等)

这个方案的优点是完全不需要网络请求,用户体验更流畅;缺点是需要同步前端和后端的筛选、排序逻辑,如果后端规则变了,前端也要跟着改,维护成本稍高。

3. 进阶方案:自定义字段政策(Field Policy)

如果你希望Apollo自动处理列表的更新,可以给getItems定义一个字段政策,在mergeread函数里处理新增条目的情况。不过这种方式更适合分页场景下的增量更新,对于多筛选排序组合的情况,还是需要结合前面的筛选判断逻辑,实现起来复杂度较高,适合对性能要求极高的场景。

总结

如果你的项目对开发效率要求更高,优先选方案1(invalidateQueries);如果追求极致的用户体验,且筛选排序逻辑相对稳定,可以试试方案2。避免用no-cache或重置整个缓存,确实会浪费Apollo缓存的优势。

备注:内容来源于stack exchange,提问作者theravencookie

火山引擎 最新活动