Apollo-client: Apollo resetStore() refetch all queries

Created on 6 Mar 2017  路  18Comments  路  Source: apollographql/apollo-client

I use it with React Native

    logout: props => () => {
        const { client, setUserid, setUserLoaded } = props; // eslint-disable-line

        clearAuthenticationToken().then(() => {
            Actions.login();

            setUserid(null);
            setUserLoaded(false);
            removeTokenInMiddleware(client);

            client.resetStore();
        }).catch(err => {
            console.log('Logout failed', err);
        });
    }

after call client.resetStore() I see Apollo refetch some queries. Why?

Most helpful comment

Yeah I get some weird behaviour on log out when using this.

I really just expect the store to equal = {} when I use resetStore not to refetch queries. How it is now I'm always getting errors saying variables for queries are null (which makes sense, they are null since the user logged out and doesn't want to make any queries).

All 18 comments

The idea is that reset store is meant to clear out information from your store, but you may have watchQuery() instances (i.e. active queries) that are subscribed to information from the store. If we were to reset everything without fetching new information, those queries would break. So, resetStore actually refetches those queries.

I just noticed that resetStore is undocumented. It would be great if we could add a description as to what it does.

cc @calebmer. Can you also document resetStore() while you're working on the docs? Thanks!

I think I have an issue with React Native Router Flux.

It sound similar or related to the issue I reported in https://github.com/apollographql/apollo-client/issues/1319

As explained in https://github.com/apollographql/apollo-client/issues/1319 this is intentional behavior. Let us know if you disagree with that decision.

There鈥檚 a PR open to document resetStore here: https://github.com/apollographql/apollo-client/pull/1435

Is it only weird to me to fetch all the store again after resetStore?
Some queries might not change if user is logged.

Why not using a param (refetchOnResetStore) to choose this?

Yeah I get some weird behaviour on log out when using this.

I really just expect the store to equal = {} when I use resetStore not to refetch queries. How it is now I'm always getting errors saying variables for queries are null (which makes sense, they are null since the user logged out and doesn't want to make any queries).

I'm also having errors because resetStore() is refetching all the queries. As stated in the docs http://dev.apollodata.com/react/auth.html#login-logout I'm using resetStore after the user logs out. I'm deleting the token when the user logs out so obviously, resetStore trying to refetch all the queries is breaking because now, it's unauthorized to do that. So, what's the recommended way of dealing with it?

@larsbs it sounds like some of the components that are still mounted in the React tree require the user to be signed in, before resetting the store, route the user away from any screens that require authentication so that the queries associated with "protected" components are not re-triggered

@larsbs just wondering if you end up solving this problem, this problem is still happening in version 2,

client.cache.reset() will actually clear the cache. may be helpful for some people
Akryum/vue-apollo#53 (comment)

2 years later, this weird behavior is still around. Apollo never disappoints!

@spyshower What "weird behavior is still around"? The issue opened here was not a bug, it was/is functioning as designed. If you're experiencing a new problem with resetStore, please open a new issue (ideally with a runnable reproduction). Thanks!

For those who stumble on this, there is new method called clearStore, which does not refetches queries.

For those of you who want to "reset" your store to an "initial" or "default" app state鈥擾before your observables raise errors accessing local cache things like an auth token or so_鈥攖hen you might like to try:

await client.clearStore();
await cache.writeData({ data: defaultState });
await client.reFetchObservableQueries();

where reFetchObservableQueries is simply the method that is called as part of the .resetStore method after running .clearStore internally.

So essentially you can reset/clear your cache of all items, prepare your cache like you did upon initialisation, like with .writeData, and then invoke the end part of the .resetStore method to get all your useQuery etc observables updated again.

@ptboyer wow amazing timing, glad I waited a few days before implementing clearing cache for auth! For me I trigger clearStore() on logout so everything is empty even though I have an auth listener. When a user logs in, within the update method in the mutation, I trigger refetchObservableQueries() and it loads in the new user in to my auth listener.

Thanks for making me aware of this method!!

@uncvrd No worries, glad I could help!

Although for me, because I have some observables mounted when the logout is called, clearStore would actually leave stale data, _as they are_, in those components, whereas re-fetching (with .reFetchObservableQueries) will give an opportunity for these currently mounted components with their useQuery hooks to now respond to the new unauthorised state, by appropriately raising auth errors, data being undefined as they should be, and allowing my components to deal with that state as needed. I only use .clearStore to defer the refetching until I've reset the cache to my "default" state as needed so that my observables, particularly those that reference the local state with @client don't raise errors with an empty store, then refetch.

For anyone else who's curious, I rigged my logout method/flow as a local ApolloClient mutation resolver:

const resolvers = {
  Mutation: {
    ...
    clearToken: async (_, __, { client }) => {
      await client.clearStore();
      await client.writeData({ data: defaultState });
      await client.reFetchObservableQueries();
      return true;
    },
    ...
  },
};

And then with a query like:

export const CLEAR_TOKEN = gql`
  mutation ClearToken {
    clearToken @client
  }
`;

We can logout the app from any component as a mutation just like every other network like request:

const [clearToken] = useMutation(CLEAR_TOKEN);
Was this page helpful?
0 / 5 - 0 ratings