23
votes

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.

3
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 serverPedro Baptista Afonso
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.Bergi

3 Answers

7
votes

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

1
votes

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 })
        }
    });
}
0
votes

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;
     }
}