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

urql缓存更新时出现重复数据问题——urql、GraphQL、React

问题分析与解决方案

核心问题根源

你遇到的重复问题本质是缓存更新时未做去重处理,加上urql GraphCache在处理参数初始化延迟(默认参数从localStorage加载)的查询时,不同参数的查询实例可能意外共享缓存引用,导致新记录被重复追加。另外,直接修改缓存返回的data对象(引用类型)会进一步加剧数据共享问题。

具体修复步骤

1. 避免直接修改缓存数据,强制创建副本+去重

urql的缓存数据是引用类型,直接修改data.readMeanings.meanings会影响其他关联查询。必须创建数组副本,并基于记录唯一标识(如id)去重:

createMeanings: (result, args, cache, info) => {
  const newMeanings = (result as CreateMeaningsMutation)
    .createMeanings.meanings;
  if (!newMeanings) return;

  cache
    .inspectFields("Query")
    .filter((field) => field.fieldName === "readMeanings")
    .forEach((field) => {
      cache.updateQuery(
        {
          query: ReadMeaningsDocument,
          variables: field.arguments as QueryReadMeaningsArgs,
        },
        (data: ReadMeaningsQuery | null) => {
          if (!data?.readMeanings?.meanings) return data;

          // 创建数据副本,避免修改原缓存引用
          const combinedMeanings = [...newMeanings, ...data.readMeanings.meanings];
          // 基于唯一id去重,保留最新的前置记录
          const uniqueMeanings = Array.from(
            new Map(combinedMeanings.map(item => [item.id, item])).values()
          );

          return {
            ...data,
            readMeanings: {
              ...data.readMeanings,
              meanings: uniqueMeanings,
            },
          };
        }
      );
    });
},

2. 过滤目标查询,避免更新无关实例

你提到存在默认参数和实际加载参数的两种readMeanings查询,可在filter阶段增加参数校验,只更新符合业务需求的查询(比如仅更新按createdAt DESC排序的查询,确保新记录显示在顶部):

.filter((field) => 
  field.fieldName === "readMeanings" &&
  field.arguments?.options?.sorting?.by === "createdAt" &&
  field.arguments?.options?.sorting?.order === "DESC"
)

3. 配置keyArgs明确缓存区分规则

在GraphCache配置中为readMeanings指定keyArgs,确保不同参数的查询被独立缓存,避免数据共享:

const cache = createGraphCache({
  resolvers: {
    Query: {
      readMeanings: {
        keyArgs: ["options"], // 将options作为缓存键的核心标识
      },
    },
  },
  // 其他配置项
});

额外建议

  • 检查组件中useQuery的调用逻辑,避免重复创建相同参数的查询实例
  • 若手动缓存更新复杂度高,可在mutation完成后通过refetchQueries主动刷新目标查询(但手动更新性能更优)

原提问内容

更新说明:
我对新记录的缓存机制进行了调查,发现以下现象:

  • 首次插入(new1)时,会在当前(首次使用的)查询中添加一条额外记录(默认查询:[new1,...],首次使用查询:[new1,new1,...])。
  • 第二次插入时,会将上一次插入的记录(new1)添加到默认查询中,同时仍会在首次使用的查询中添加一条额外记录(默认查询:[new2,new1,new1,...],首次使用查询:[new2,new2,new1,new1,...],第二次查询:[new2,new1,...]——此查询结果正确)。
  • 后续每次插入都会重复上述第二步的情况,但第二次及之后使用的查询不受影响(我已检查最多四个查询的情况)。

我有createMeanings mutation和readMeanings query。当创建Meaning类型的新记录后,希望它显示在表格顶部。

readMeanings的参数如下:{options: {limit: 5, sorting: {by: "createdAt", order: "DESC"}}}。因此我存在多个readMeanings查询实例。

问题在于,新创建的记录经常(但并非总是)在缓存中出现重复,甚至重复多次。

以下是我参考官方文档编写的缓存更新代码:

createMeanings: (result, args, cache, info) => {
  const newMeanings = (result as CreateMeaningsMutation)
    .createMeanings.meanings;
  if (newMeanings) {
    cache
      .inspectFields("Query")
      .filter((field) => field.fieldName === "readMeanings")
      .forEach((field) => {
        cache.updateQuery(
          {
            query: ReadMeaningsDocument,
            variables: field.arguments as QueryReadMeaningsArgs,
          },
          (data: ReadMeaningsQuery | null) => {
            if (data?.readMeanings.meanings) {
              console.log("field.arguments:", field.arguments);
              console.log("newMeanings", newMeanings);
              data.readMeanings.meanings = [
                ...newMeanings,
                ...data.readMeanings.meanings,
              ];
              // Or: data.readMeanings.unshift(...newMeanings);
            }
            console.log("data", data);
            return data;
          }
        );
      });
  }
},

查看日志时,我看到如下内容:
[Log] field.arguments: – {options: {limit: 10, sorting: {by: "updatedAt", order: "DESC"}}}*
data.readMeanings.meanings has 6 records

[Log] field.arguments: – {options: {limit: 5, sorting: {by: "createdAt", order: "DESC"}}}
data.readMeanings.meanings has 7 records

在这7条记录中,顶部的两条是新创建记录的重复项。

看起来data似乎在这两个查询之间被共享了。

是否有什么我忽略的明显问题?希望能得到相关建议!

*不确定是否相关,但这些是默认参数,我通过useEffect从localStorage加载实际参数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 21:20:15