10

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?

Soviut
  • 88,194
  • 49
  • 192
  • 260
Thomas Rositsky
  • 177
  • 1
  • 3
  • 10
  • 4
    in other words: "your queried (requested) `movie` [type] should contain `id` property" (beside `name`, `description` or `actors`) - otherwise it is not cache'able - [you can use other named unique field and conversion function] - cache just works this way, it wants unique objects – xadm Jul 27 '20 at 21:15
  • 1
    "*ensure all objects of type Movie have IDs*" is quite clear imo – Bergi Jul 27 '20 at 21:46

4 Answers4

9

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);
          },
        },
      },
    },
  },
});
Zeeyed
  • 152
  • 1
  • 5
4

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
            }
          }
        }
      }
    }
  })
});
Thomas Rositsky
  • 177
  • 1
  • 3
  • 10
3

Had same issue with inconsistency of data values vs. our schema. A value type within an entity was missing the id value. Caused by an incomplete data migration.

Temporary solution:

const typePolicies = {
      PROBLEM_TYPE: {
        keyFields: false as false,
      },
      PARENT_TYPE: {
        fields: {
          PROBLEM_FIELD: {
            merge: true
          }
        }
      }
    }
bdargan
  • 1,309
  • 8
  • 16
2

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.

Ben Regenspan
  • 10,058
  • 2
  • 33
  • 44
  • I'm confused; why wouldn't that be the default behavior for types with an `id` field. Apollo can tell two objects are the same object if they have the same id, so just merge them. – Tyler Jul 31 '21 at 19:10
  • @matrixfrog it is the default behavior for types with an `id` field, this setup is only for special cases where one is not available for whatever reason (definitely preferable to design the API side such that this isn't necessary). (Just updated my answer to be clear on this) – Ben Regenspan Aug 01 '21 at 22:58
  • Okay that makes sense, but I was still getting a warning, even with `id`s on all objects. However, since posting that comment, I think I solved it by upgrading to the latest Apollo Client version. – Tyler Aug 02 '21 at 23:02