Apollo GraphQL 合并缓存数据

IT技术 javascript reactjs caching graphql apollo
2021-04-30 08:11:56

我有一个由 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 可以安全地合并这些对象:{ ... }

谷歌浏览器可以正常工作,但此错误会影响 Safari 浏览器。一切都在粉碎。我 100% 确定这是因为此警告消息。在第一个请求中,我在缓存中设置了电影数据,在对同一查询的第二个请求中,我只是用新数据替换了旧数据,因此以前的缓存数据未定义。我该如何解决这个问题?

4个回答

解决了!

 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
            }
          }
        }
      }
    }
  })
});

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

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

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

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

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

数据值与我们的模式不一致也有同样的问题实体中的值类型缺少id值。由不完整的数据迁移引起。

临时解决方案:

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