Search code examples
reactjsapolloreact-apolloapollo-client

Reset Apollo store and authenticated queries on logout


I'm trying to clear my Apollo store when users log out of my app, but having no luck getting everything to update correctly.

Currently I am conditionally displaying authenticated/unauthenticated routes based on a current user being present. The endpoint for this relies on a token in the header. This token is set on login and persisted.

export default function App() {
  const { client, data, loading } = useQuery(CURRENT_USER, {
    onCompleted({ currentUser }) {
      client.writeData({ data: { currentUser } });
    }
  });

  if (loading) return null;

  return (
    <BrowserRouter>
      {data.currentUser ? <Authenticated /> : <Unauthenticated />}
    </BrowserRouter>
  );
};

There are several resources an authenticated user can view/touch while logged in, each with queries of their own.

export default function Zones() {
  const { data, loading } = useQuery(ZONES);

  if (loading) return null;

  return (
    <div className='Zones'>
      ...
    </div>
  );
}

The issue I'm facing is that I cannot clear the store completely when users log out. In my signOut function I'm calling client.resetStore(), which I understand will refetch active queries and thus will cause my server to respond with unauthorized requests.

const signOut = () => {
  localStorage.setItem('token', null);
  client.resetStore();
};

My confusion is that even if I adjust my signOut to clear the current user in the store and send me to the Unauthorized container, when resetStore() is called, it fetches all of the stale queries as well.

I've tried using clearStore(), my components don't re-render and the existing queries persist, so I get errors about not being able to read properties off of currentUser, when none of those components should be present anymore.

I have also tried client.writeQuery and changing the CURRENT_USER query to return nothing, but the rest of the data is still present and won't work if it's a distinct resource query (like by an ID that is owned by the first user).


Solution

  • I'm still open to other approaches to solving this, but this is what is now working for me.

    This clears the store of all past data and then refetches the original query. For some reason I can not get the App query to update if I call writeData or writeQuery in the component with the sign out button.

    export default function App() {
      const { client, data, loading, refetch } = useQuery(CURRENT_USER, {
        onCompleted({ currentUser }) {
          client.writeData({ data: { currentUser } });
        }
      });
    
      if (loading) return null;
    
      return (
        <BrowserRouter>
          <CurrentUserContext.Provider value={refetch}>
            {data.currentUser ? <Authenticated /> : <Unauthenticated />}
          </CurrentUserContext.Provider>
        </BrowserRouter>
      );
    };
    
      const client = useApolloClient();
      const refetchCurrentUser = useContext(CurrentUserContext);
    
      const signOut = () => {
        localStorage.setItem('token', null);
        client.clearStore().then(refetchCurrentUser);
      };