Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 415
Jean-Baptiste Rudant Avatar asked Feb 03 '18 10:02

Jean-Baptiste Rudant


People also ask

How do I clear the Apollo Client cache?

Resetting the cache Sometimes, you might want to reset the cache entirely, such as when a user logs out. To accomplish this, call client. resetStore . This method is asynchronous, because it also refetches any of your active queries.

Can I delete Apollo cache?

Apollo Client 3 enables you to selectively remove cached data that is no longer useful. The default garbage collection strategy of the gc method is suitable for most applications, but the evict method provides more fine-grained control for applications that require it.

Does Apollo Client cache?

Overview. Apollo Client stores the results of your GraphQL queries in a local, normalized, in-memory cache. This enables Apollo Client to respond almost immediately to queries for already-cached data, without even sending a network request. The Apollo Client cache is highly configurable.


2 Answers

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

like image 131
Martin Hunt Avatar answered Oct 12 '22 03:10

Martin Hunt


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 })
        }
    });
}
like image 39
andrey Avatar answered Oct 12 '22 03:10

andrey