3
votes

I'm working on building an authentication mechanism over graphql, and I'm trying to figure out why a graphql-connected component isn't rerendering after relogin... for example:

  • At /users I have a react-apollo graphql-connected Users component that requests a list of users.
  • The server will return an authentication error if no token is provided; the component renders a <Redirect> to the /login route; after successful login, the Login component stashes the token and redirects back.
  • The Users component wrapper starts the graphql request and renders "loading..." in the meantime. When the graphql request succeeds, it rerenders and the users appear, yay.
  • If you Sign Out from that page, the Logout component at /logout discards the token then redirects back; the Users component's request gets the authentication error again and sends you to '/login'.
  • After another successful login, you're sent back to '/users'; again it starts a graphql request to the server (and renders "loading..."), but this time, when the request succeeds, the component isn't updated again.

I can see that the graphql request succeeds (and have watched in Chrome's debugger as the APOLLO_QUERY_RESULT action is handled by react-apollo's reducer and updates the state in the store).

I've tried to find where React is checking to see if the component's props have changed, but I'm enough of a React debugging noob that I haven't figured out where to find that code in the web inspector: maybe something I don't understand about how React is packaged for distribution.

I clear out the ApolloClient's store (by calling resetStore()) on both login and logout, since I don't want to accidentally reuse data from the other authenticatedness; however, removing these calls doesn't get rid of the problem. Interestingly (?), if I force the connection to bypass the cache by providing { options: { fetchPolicy: 'network-only' } } in the graphql() call, the problem goes away. (Not a viable solution - I'd like to benefit from the cache generally.)

I've built a stripped-down example: https://github.com/bryanstearns/apollo-auth-experiment and you can see it in a CodeSandbox: https://codesandbox.io/s/m4nlpp86j (you'll probably want to access the running example from an independent browser window at https://m4nlpp86j.codesandbox.io/ because the sandbox editor kinda makes the web debug extensions act weird).

1

1 Answers

3
votes

To fix this behavior, modify your graphql HOC to include notifyOnNetworkStatusChange in the options.

export const Users = graphql(usersQuery, { options: { notifyOnNetworkStatusChange: true } })(RawUsers);

I don't think you should have to do that -- I think data.loading is supposed to accurately reflect the status of your query regardless of that option being set to true, unlike data.networkStatus but it looks like it's a known bug.

As far as resetStore -- it doesn't actually wipe your entire store, but rather wipes away your store and refetches all your active queries. If you wanted to blow away your store, since you're already integrating Redux with Apollo, the easiest thing to do would be to create an action to do that.

You may also want to consider a session-based authentication mechanism, rather than relying on the client to persist a token. It's pretty simple to implement server-side, would not only involve less work on the client-side (don't have to remember to pass the token in with every request), and would let you keep your user logged in after they navigate away from the page.