Apollo GraphQL merge cached data
Solution 1
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
}
}
}
}
}
})
});
Solution 2
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);
},
},
},
},
},
});
Solution 3
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.
Solution 4
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
}
}
}
}
Thomas Rositsky
Updated on June 14, 2022Comments
-
Thomas Rositsky almost 2 years
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?
-
xadm almost 4 yearsusing
id
in both queries does the same -
Admin over 3 yearsI had a similar issue and I am retuning ids in both, but it doesn't work for me @xadm
-
Baruch over 3 years@xadm My man... was about to start pulling my hair before I saw your comment.
-
Tyler almost 3 yearsI'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. -
Ben Regenspan almost 3 years@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) -
Tyler over 2 yearsOkay 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.