SmxCde
SmxCde

Reputation: 5413

Apollo useQuery() - "refetch" is ignored if the response is the same

I am trying to use Apollo-client to pull my users info and stuck with this problem:

I have this Container component responsible for pulling the user's data (not authentication) once it is rendered. User may be logged in or not, the query returns either viewer = null or viewer = {...usersProps}.

Container makes the request const { data, refetch } = useQuery<Viewer>(VIEWER);, successfully receives the response and saves it in the data property that I use to read .viewer from and set it as my current user.

Then the user can log-out, once they do that I clear the Container's user property setUser(undefined) (not showed in the code below, not important).

The problem occurred when I try to re-login: Call of refetch triggers the graphql http request but since it returns the same data that was returned during the previous initial login - useQuery() ignores it and does not update data. Well, technically there could not be an update, the data is the same. So my code setUser(viewer); does not getting executed for second time and user stucks on the login page.

  const { data, refetch } = useQuery<Viewer>(VIEWER);

  const viewer = data && data.viewer;

  useEffect(() => {
    if (viewer) {
      setUser(viewer);
    }

  }, [ viewer ]);

That query with the same response ignore almost makes sense, so I tried different approach, with callbacks:

  const { refetch } = useQuery<Viewer>(VIEWER, {
    onCompleted: data => {
      if (data.viewer) {
        setUser(data.viewer);
      }
    }
  });

Here I would totally expect Apollo to call the onCompleted callback, with the same data or not... but it does not do that. So I am kinda stuck with this - how do I make Apollo to react on my query's refetch so I could re-populate user in my Container's state?

Upvotes: 0

Views: 6620

Answers (1)

Shyam
Shyam

Reputation: 114

This is a scenario where apollo's caches come handy. Client

import { resolvers, typeDefs } from './resolvers';

let cache = new InMemoryCache()
const client = new ApolloClient({
  cache,
  link: new HttpLink({
    uri: 'http://localhost:4000/graphql',
    headers: {
      authorization: localStorage.getItem('token'),
    },
  }),
  typeDefs,
  resolvers,
});

cache.writeData({
  data: {
    isLoggedIn: !!localStorage.getItem('token'),
    cartItems: [],
  },
})

LoginPage

const IS_LOGGED_IN = gql`
  query IsUserLoggedIn {
    isLoggedIn @client
  }
`;

function IsLoggedIn() {
  const { data } = useQuery(IS_LOGGED_IN);
  return data.isLoggedIn ? <Pages /> : <Login />;
}

onLogin

function Login() {
  const { data, refetch } = useQuery(LOGIN_QUERY);
  let viewer = data && data.viewer
  if (viewer){
    localStorage.setItem('token',viewer.token)
  }
  // rest of the stuff
}

onLogout

onLogout={() => {
        client.writeData({ data: { isLoggedIn: false } });
        localStorage.clear();
      }}

For more information regarding management of local state. Check this out.

Hope this helps!

Upvotes: 2

Related Questions