Deleting Apollo Client cache for a given query and every set of variables
Asked Answered
C

3

30

I have a filtered list of items based on a getAllItems query, which takes a filter and an order by option as arguments.

After creating a new item, I want to delete the cache for this query, no matter what variables were passed. I don't know how to do this.

I don't think updating the cache is an option. Methods mentionned in Apollo Client documentation (Updating the cache after a mutation, refetchQueries and update) all seem to need a given set of variables, but since the filter is a complex object (with some text information), I would need to update the cache for every given set of variables that were previously submitted. I don't know how to do this. Plus, only the server does know how this new item impact pagination and ordering.

I don't think fetch-policy (for instance setting it to cache-and-network) is what I'm looking for, because if accessing the network is what I want after having created a new item, when I'm just filtering the list (typing in a string to search), I want to stay with the default behavior (cache-only).

client.resetStore would reset the store for all type of queries (not only the getAllItems query), so I don't think it's what I'm looking for either.

I'm pretty sure I'm missing something here.

Clandestine answered 3/2, 2018 at 10:21 Comment(2)
I'm not totally clear about your needs here. But seems like using fetchPolicy for the getAllItems query, would force all the search to come from the serverHarv
If you use cache.modfiy in the update option of the mutation, it will call your callback function for all argument variants it has cached for the getAllItems field, allowing you to remove the deleted item from any of them.Vincentia
T
10

There's no officially supported way of doing this in the current version of Apollo but there is a workaround.

In your update function, after creating an item, you can iterate through the cache and delete all nodes where the key starts with the typename you are trying to remove from the cache. e.g.

// Loop through all the data in our cache
// And delete any items where the key start with "Item"
// This empties the cache of all of our items and 
// forces a refetch of the data only when it is next requested.
Object.keys(cache.data.data).forEach(key => 
  key.match(/^Item/) && cache.data.delete(key)
)

This works for queries that exist a number of times in the cache with different variables, i.e. paginated queries.

I wrote an article on Medium that goes in to much more detail on how this works as well as an implementation example and alternative solution that is more complicated but works better in a small number of use cases. Since this article goes in to more detail on a concept I have already explained in this answer, I believe it is ok to share here: https://medium.com/@martinseanhunt/how-to-invalidate-cached-data-in-apollo-and-handle-updating-paginated-queries-379e4b9e4698

Toombs answered 25/10, 2018 at 18:47 Comment(2)
"... and // forces a refetch of the data only when it is next requested.". This is exactly the opposite of what I'm trying to achieve. I.e. is there a way to do the same and force a refetch of the data, exactly at the time of deletion?Lophophore
I tried this but after the cache is deleted, my <Query> component reloads with no data (before data.items = [.. my items..], after cache is removed data.items = undefined). error and loading are both false. So the Query component doesn't correctly reload the data from the graphql service.Degree
Q
6

this worked for me (requires apollo 2 for cache eviction feature) - clears query matched by regexp from cache

after clearing cache query will be automatically refeteched without need to trigger refetch manually (if you are using angular: gql.watch().valueChanges will perform xhr request and emit new value)

export const deleteQueryFromCache = (cache: any, matcher: string | RegExp): void => {
    const rootQuery = cache.data.data.ROOT_QUERY;
    Object.keys(rootQuery).forEach(key => {
        if (key.match(matcher)) {
            cache.evict({ id: "ROOT_QUERY", fieldName: key })
        }
    });
}
Quenelle answered 12/10, 2020 at 22:59 Comment(0)
P
0

ngrx like

resolvers = {
    removeTask(
       parent,
       { id },
       { cache, getCacheKey }: { cache: InMemoryCache | any; getCacheKey: any }
     ) {
       const key = getCacheKey({ __typename: "Task", id });
       const { [key]: deleted, ...data } = cache.data.data;
       cache.data.data = { ...data };
       return id;
     }
}
Priddy answered 27/5, 2019 at 2:59 Comment(1)
Note that resolvers are deprecated. See apollographql.com/docs/react/local-state/local-resolversKillian

© 2022 - 2024 — McMap. All rights reserved.