Unable to clear apollo-client cache on logout

Viewed 804

I have read through a couple other posts as well as a few github issues, and I am yet to find a solution. When I logout as one user, and sign in as a different user, the new user will appear for a split second and then be replaced by the previous user's data.

Here is my attempt to go nuclear on the cache:

onClick={() => {
  client
    .clearStore()
    .then(() => client.resetStore())
    .then(() => client.cache.reset())
    .then(() => client.cache.gc())
    .then(() => dispatch(logoutUser))
    .then(() => history.push('/'));
}}

I've tried getting the client object from both these locations (I am using codegen):

const { data, loading, error, client } = useUserQuery();
const client = useApolloClient();

Here is my Apollo client setup:

const apolloClient = new ApolloClient({
  uri: config.apiUrl,
  headers: {
    uri: 'http://localhost:4000/graphql',
    Authorization: `Bearer ${localStorage.getItem(config.localStorage)}`, 
  },
  cache: new InMemoryCache(),
});

When I login with a new user, I writeQuery to the cache. If I log the data coming back from the login mutation, the data is perfect, exactly what I want to write:

sendLogin({
  variables: login,
  update: (store, { data }) => {
    store.writeQuery({
      query: UserDocument,
      data: { user: data?.login?.user },
    });
  },
})

UserDocument is generated from codegen:

export const UserDocument = gql`
    query user {
  user {
    ...UserFragment
  }
}
    ${UserFragmentFragmentDoc}`;

Following the docs, I don't understand what my options are, I have tried writeQuery, writeFragment, and cache.modify and nothing changes. The Authentication section seems to suggest the same thing I am trying.

Seems like all I can do is force a window.location.reload() on the user which is ridiculous, there has to be a way.

1 Answers

Ok, part of me feels like a dumb dumb, the other thinks there's some misleading info in the docs.

despite what this link says:

const client = new ApolloClient({
  cache,
  uri: 'http://localhost:4000/graphql',
  headers: {
    authorization: localStorage.getItem('token') || '',
    'client-name': 'Space Explorer [web]',
    'client-version': '1.0.0',
  },
  ...
});

These options are passed into a new HttpLink instance behind the scenes, which ApolloClient is then configured to use.

This doesn't work out of the box. Essentially what is happening is my token is being locked into the apollo provider and never updating, thus the payload that came back successfully updated my cache but then because the token still contained the old userId, the query subscriptions overwrote the new data from the new user's login. This is why refreshing worked, because it forced the client to re-render with my local storage.

The fix was pretty simple:

  // headerLink :: base headers for graphql queries
  const headerLink = new HttpLink({ uri: 'http://localhost:4000/graphql' });

  // setAuthorizationLink :: update headers as localStorage changes
  const setAuthorizationLink = setContext((request, previousContext) => {
    return {
      headers: {
        ...previousContext.headers,
        Authorization: `Bearer ${localStorage.getItem(config.localStorage)}`,
      },
    };
  });

  // client :: Apollo GraphQL Client settings
  const client = new ApolloClient({
    uri: config.apiUrl,
    link: setAuthorizationLink.concat(headerLink),
    cache: new InMemoryCache(),
  });

And in fact, I didn't even need to clear the cache on logout.

Hope this helps others who might be struggling in a similar way.

Related