问题
I am following a tutorial on GraphQL, in the video the author does not use refetchQueries for a deleteMutation and all works well with UI updates and mutation. But here in the project sandbox code is updated and refetchQuery is now used for this operatio on Job component -> line 20 -> deleteJob(): codeSandBox.
I have this similar problem in my app that does not update the UI automatically without refetchQueries done everywhere. Shouldn't Apollo be applying automatically the cache of Apollo via apollo-cache-inmemory, perform mutation and update UI in this kind of mutation if I understand it right.
Example out of the box with apollo-boost:
export default gql`
mutation deleteItem($id: uuid!) {
delete_item(where: {id:{_eq: $id }}){
returning {
id
}
}
}`;
const onDeleteItem = (id) => {
deleteItem({
variables: { id },
});
};
Any suggestions or experiences on this?
回答1:
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 });
}
});
来源:https://stackoverflow.com/questions/58633865/why-is-refetchqueries-needed