【问题标题】:Apollo GraphQL merge cached dataApollo GraphQL 合并缓存数据
【发布时间】:2020-11-17 06:29:14
【问题描述】:

我有一个由 2 个组件组成的页面,每个组件都有自己的数据请求 例如

<MovieInfo movieId={queryParamsId}/>

const GET_MOVIE_INFO = `gql
  query($id: String!){
   movie(id: $id){
    name
    description
 }
}`

下一个组件

<MovieActors movieId={queryParamsId}/>

const GET_MOVIE_ACTORS = `gql
  query($id: String!){
   movie(id: $id){
    actors
 }
}`

对于每个查询,我都使用 apollo hook

const { 数据、加载、错误 } = useQuery(GET_DATA, {variable: {id: queryParamsId}}))

一切都很好,但我收到了一条警告消息:

替换 Query 对象的电影字段时,缓存数据可能会丢失。 为了解决这个问题(这不是 Apollo Client 中的错误),要么确保所有 Movie 类型的对象都有 ID,要么为 Query.movi​​e 字段定义自定义合并函数,以便 InMemoryCache 可以安全地合并这些对象: { ... }

在 google chrome 上运行正常,但此错误会影响 Safari 浏览器。一切都令人崩溃。我 100% 确定这是因为这个警告信息。在第一个请求中,我在缓存中设置了电影数据,在对同一查询的第二个请求中,我只是将旧数据替换为新数据,因此之前的缓存数据是未定义的。我该如何解决这个问题?

【问题讨论】:

  • 换句话说:“您的查询(请求)movie [类型] 应该包含id 属性”(在namedescriptionactors 旁边) - 否则它不是cache'able - [你可以使用其他命名的唯一字段和转换函数] - 缓存就是这样工作的,它需要唯一的对象
  • 确保所有 Movie 类型的对象都有 ID”很清楚 imo

标签: javascript reactjs caching graphql apollo


【解决方案1】:

解决了!

 cache: new InMemoryCache({
    typePolicies: {
      Query: {
        fields: {
          YOUR_FIELD: {
            merge(existing = [], incoming: any) {
              return { ...existing, ...incoming };
              // this part of code is depends what you actually need to do, in my 
              case i had to save my incoming data as single object in cache
            }
          }
        }
      }
    }
  })
});

【讨论】:

  • 在两个查询中使用 id 效果相同
  • 我遇到了类似的问题,我正在重新调整两者的 ID,但这对我不起作用@xadm
  • @xadm 我的男人......在我看到你的评论之前就开始扯我的头发了。
【解决方案2】:

这是 Thomas 提到的相同解决方案,但要短一些

const cache = new InMemoryCache({
  typePolicies: {
    Query: {
      fields: {
        YOUR_FIELD: {
          // shorthand  
          merge: true,
        },
      },
    },
  },
});

这和下面的一样

const cache = new InMemoryCache({
  typePolicies: {
    Query: {
      fields: {
        YOUR_FIELD: {
          merge(existing, incoming, { mergeObjects }) {
            return mergeObjects(existing, incoming);
          },
        },
      },
    },
  },
});

【讨论】:

  • 什么是true
  • 宝贝不要false
  • @simPod true 是当您有重复合并功能时使用的简写,它意味着合并现有和传入的对象。和options.mergeObjects(existing, incoming)一样,options是merge函数提供的第三个参数。
【解决方案3】:

其他答案仍然有效,但从 Apollo Client >= 3.3 开始,有一个 easier option 不需要指定特定字段或自定义合并函数。相反,您只需指定类型,它将合并该类型的所有字段:

const cache = new InMemoryCache({
  typePolicies: {
    YOUR_TYPE_NAME: {
      merge: true,
    }
  }
});

从您的示例查询中,我猜想 id 字段应该可用吗?尝试在查询中请求 ID,这应该会以更理想的方式解决问题。

【讨论】:

  • 我很困惑;为什么这不是具有 id 字段的类型的默认行为。如果两个对象具有相同的 id,Apollo 可以判断它们是同一个对象,因此只需将它们合并即可。
  • @matrixfrog 它是具有id 字段的类型的默认行为,此设置仅适用于由于某种原因无法使用的特殊情况(绝对最好设计 API 端,这样没有必要)。 (刚刚更新了我的答案以明确这一点)
  • 好吧,这是有道理的,但我仍然收到警告,即使所有对象上都有ids。但是,自从发布该评论后,我想我通过升级到最新的 Apollo Client 版本解决了这个问题。
【解决方案4】:

数据值与我们的架构不一致有同样的问题。实体中的值类型缺少 id 值。 由于数据迁移不完整。

临时解决方案:

const typePolicies = {
      PROBLEM_TYPE: {
        keyFields: false as false,
      },
      PARENT_TYPE: {
        fields: {
          PROBLEM_FIELD: {
            merge: true
          }
        }
      }
    }

【讨论】:

    猜你喜欢
    • 2018-10-16
    • 2020-07-07
    • 2019-03-01
    • 2020-02-12
    • 2019-01-31
    • 2020-09-04
    • 2021-08-08
    • 2020-02-26
    • 2021-05-09
    相关资源
    最近更新 更多