Apollo GraphQL合并缓存数据[英] Apollo GraphQL merge cached data

本文是小编为大家收集整理的关于Apollo GraphQL合并缓存数据的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我有一个由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}}))

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

替换查询对象的电影字段时可能会丢失缓存数据. 要解决此问题(这不是Apollo客户端中的错误),请确保类型电影的所有对象都有ID,或为查询字段定义自定义合并函数,因此InmemoryCache可以安全地合并这些对象:{... }

与Google Chrome可以使用,但是此错误会影响Safari浏览器.一切都在粉碎.我100%确定这是因为此警告消息.在第一个请求中,我在缓存中将电影数据设置为同一查询,我刚刚用新数据替换旧数据,因此以前的缓存数据未定义.我该如何解决这个问题?

推荐答案

已解决!

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

其他推荐答案

这是托马斯提到的相同解决方案,但有点短

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

其他推荐答案

其他答案仍然可以工作,但是从Apollo客户端> = 3.3 更轻松的选项这不需要指定特定字段或定制合并函数.相反,您只需要指定类型,它将合并该类型的所有字段:

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

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

本文地址:https://www.itbaoku.cn/post/1938107.html

问题描述

I have a page that consists of 2 components and each of them has its own request for data for example

<MovieInfo movieId={queryParamsId}/>

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

Next component

<MovieActors movieId={queryParamsId}/>

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

For each of these queries I use apollo hook

const { data, loading, error } = useQuery(GET_DATA, {variable: {id: queryParamsId}}))

Everything is fine, but I got a warning message:

Cache data may be lost when replacing the movie field of a Query object. To address this problem (which is not a bug in Apollo Client), either ensure all objects of type Movie have IDs, or define a custom merge function for the Query.movie field, so InMemoryCache can safely merge these objects: { ... }

It's works ok with google chrome, but this error affects Safari browser. Everything is crushing. I'm 100% sure it's because of this warning message. On the first request, I set Movie data in the cache, on the second request to the same query I just replace old data with new, so previous cached data is undefined. How can I resolve this problem?

推荐答案

Solved!

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

其他推荐答案

Here is the same solution mentioned by Thomas but a bit shorter

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

This is same as the following

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

其他推荐答案

The other answers still work, but as of Apollo Client >= 3.3 there's an easier option that doesn't require specifying specific fields or a custom merge function. Instead, you only have to specify the type and it will merge all fields for that type:

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

From your example query, I'd guess that an id field should be available though? Try requesting the ID in your query, that should solve the problem in a much more ideal way.