The answer is relatively simple: There is no universal way in GraphQL to tell a client that an entity was deleted. Let's first compare this to an update mutations. Imagine we are updating one of the jobs that we already have in our cache. First the cache (simplified, not actually quite how it looks inside of Apollo):
{
"Query": {
"jobs": ["Job:1", "Job:2"],
},
"Job:1": {
"__typename": "Job",
"id": 1,
"company": "Big Corp",
"title": "Sales Specialist"
},
"Job:2": {
"__typename": "Job",
"id": 2,
"company": "Big Corp",
"title": "GraphQL Expert"
}
}
If Apollo now gets an answer from an update mutation that looks like the following:
{
"data": {
"updateJob": {
"__typename": "Job",
"id": 2,
"company": "Big Corp",
"title": "GraphQL Unicorn"
}
}
}
It can use the dataIdFromObject function to understand that the object belongs to the cache key "Job:2" in our normalised cache. Apollo can assume that this version is newer than the old one and merge the keys with preference of the newer result. Our cache now looks like this:
{
"Query": {
"jobs": ["Job:1", "Job:2"],
},
"Job:1": { ... },
"Job:2": {
"__typename": "Job",
"id": 2,
"company": "Big Corp",
"title": "GraphQL Unicorn" // updated!
}
}
Then the "jobs" query will automatically update with the new job because it is just referencing the job and is not storing the entity itself. Great! But now compare the result from the delete function:
{
"data": {
"deleteJob": {
"returning": {
"id": 2,
}
}
}
}
The result of this query could be anything. Apollo cannot know that you have just deleted a job with a certain id. Maybe if GraphQL had something in the specification like a magical "__isDeleted" and we would get something like:
{
"data": {
"deleteJob": {
"__typename": "Job",
"__isDeleted": true,
"id": 2,
}
}
}
}
We could give our cache implementation the hint that entities with __isDeleted: true should be removed from all referencing queries. But unfortunately this does not exists. This is not to bad though, we can either use refetchQuery to trigger a refetch of the other query or we can manually update the other query:
const deleteJob = useMutation(DELETE_JOB, {
update(store, response) {
const data = store.readQuery({ query: GET_JOBS });
data.jobs = data.jobs.filter(job => job.id !== response.deleteJob.returning.id);
store.writeQuery({ query: GET_JOBS, data });
}
});