Reputation: 1004
I'm unclear on how to work with the ApolloClient InMemoryCache
in regards to fields that have nesting.
For example, I've got a GraphQL mutation that, when marking a todo "completed," will also mark all of its children "completed." On the backend, a child
is a relationship between parent_id
" and id
.
"data": {
"upsertTodos": [
{
"todo": {
"__typename": "rc_todos",
"is_completed": true,
"label": "Go to the store",
"id": 1252,
"parent_id": null
"children": [
{
"__typename": "rc_todos",
"id": 1040,
"is_completed": true,
"label": "Buy some milk",
"parent_id": 1252
}
],
}
}
]
}
So, both these items are todos (same __typename
) and they both have id
. I want to make sure the cache "understands" them in both their nested and unnested state.
parent_id
and
id
or is there something I can / should do to make sure it understands this in order to handle
normalization and denormalization properly?ALL_TODOS
which so far has fetched a "flat" list of all todos. If I writeQuery
against ALL_TODOS
just updating the "Go to the store" todo - with "Buy some milk" in "children", as in the above response- does the cache understand that the "root level" "Buy some milk" todo should be updated? (Since it sees that __typename
and id
are the same) Or do I need to manually do some transformation in the update function of the mutation for this to work?InMemoryCache
with data that is sometimes queried
"flat" and sometimes "nested" in this manner?Upvotes: 1
Views: 1406
Reputation: 84807
The cache normalizes the data from the response by only storing references to objects returned by the server. If a field resolved to an object, that object will be pulled out and cached separately and the value of the field will just be a reference to that object (i.e. the cache key created by combining the __typename
and id
fields). If a field resolved to a list of objects, each object in the list will be pulled out and cached separately and the value of the field will just be an array of references to each object.
Since the objects are cached according to the aforementioned cache key, it doesn't matter how a query returns a particular object -- if the object is in the response, it will override what's already in the cache. Any parent/child relationships are irrelevant to the mechanism. The same goes for manual writes to the cache.
When you're just mutating an object that's already in the cache, the key is for the server to return the mutated object somewhere in its response -- as long as it does that, the cache will be updated to reflect whatever changes were made to the object.
What gets tricky are mutations that impact an object's membership in a list. You might, for example, have a query that returns a list of completed to-dos and another query that returns a list of pending to-dos. The cache will store an array of cache keys for each query matching the appropriate to-do objects. If a mutation changes the status of a to-do from pending to completed, Apollo has no way to know it needs to remove it from the one query and add it to the other (this is business logic that only your server knows). In this case, we have to do a manual write to the cache and update the queries ourselves.
The same principle applies to creating or deleting a todo -- Apollo has no way of knowing "this mutation created a todo", and even if it did, it would have no way to know which lists it should be added to.
Upvotes: 4