Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apollo GraphQL merge cached data

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?

like image 349
Thomas Rositsky Avatar asked Jul 27 '20 21:07

Thomas Rositsky


People also ask

How does Apollo GraphQL cache work?

Apollo Client stores the results of your GraphQL queries in a local, normalized, in-memory cache. This enables Apollo Client to respond almost immediately to queries for already-cached data, without even sending a network request. The Apollo Client cache is highly configurable.

How do I clean my Apollo cache?

In your case, you can use the apollo's method client. resetStore(); It will clear the previous cache and then load the active queries.

Does GraphQL cache data?

Now, caching in GraphQL can be done server-side. This means that the GraphQL server can be configured to fetch the response from its cache in the server without running the resolvers.

How do I write data to the Apollo client cache?

In addition to reading "random-access" data from the Apollo Client cache with readFragment, you can write data to the cache with the writeFragment method. Any changes you make to cached data with writeFragment are not pushed to your GraphQL server.

How do I execute a GraphQL query on the cache?

The readQuery method enables you to execute a GraphQL query directly on your cache, like so: query ReadTodo($id: ID!) { variables: { // Provide any required variables here. Variables of mismatched types will return `null`. If your cache contains data for all of the query's fields, readQuery returns an object that matches the shape of the query:

What is a merge function in GraphQL?

If you define a merge function for a field, the cache calls that function whenever the field is about to be written with an incoming value (such as from your GraphQL server). When the write occurs, the field's new value is set to the merge function's return value, instead of the original incoming value.

What is the Apollo client used for?

The Apollo Client is used to fetch data from any GraphQL server. The client is small, yet flexible with many awesome features of which the most appreciated one might be the automatic cache updates that come with the client.


2 Answers

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
            }
          }
        }
      }
    }
  })
});
like image 53
Thomas Rositsky Avatar answered Sep 19 '22 23:09

Thomas Rositsky


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);
          },
        },
      },
    },
  },
});
like image 28
Zeeyed Avatar answered Sep 19 '22 23:09

Zeeyed