Should I Directly Access Data From the Apollo Client or From React Component State?

Responses (0)

Clap
1|0|

Consider the following code snippet of a React component, <App />, that...

  • Runs a mutate function that authenticates the user on the client-side if they have a valid token upon. This happens upon mounting the <App /> component.

  • Stores an authenticated user's information in a user state variable upon successful authentication.

You may have noticed that the data sent back by the mutation provides the user's information in a logIn field, and any data returned from a successful mutation automatically gets added to the local Apollo Client cache.

Therefore, why do we have a user state variable when we could just access the user's information via the data field in the mutation result object? For example, like this:

This can be considered an anti-pattern, but data can be either undefined or { logIn: { id: ..., token: ..., ... } }. Therefore, you would need to check if data is undefined or not directly in the body (and rendering section) of the <App />component. Even after you determine that data is not undefined, you would still need to perform the same number of checks as before for the logIn property, etc. By using the setUser approach, you start with a baseline user object with its properties initialized to null, so you don't have to check if the user is undefined in the body (and rendering section) of the <App /> component (one less check). Additionally, with this approach, you only perform the checks for the data inside the onCompleted function.

You could directly access the cache via the update function, which is called after the mutation completes and provides the cache as an argument, like so:

However, the cache at this point doesn't actually have user data in the cache (to confirm this, print JSON.stringify(cache.data.data) in the update function). The user data is provided separately as the update function's second argument.

You would need to manually modify the cache so that it has this user. Once the cached data is updated, the change gets broadcasted across the application and re-renders the components with active queries that correspond to the updated data. So you would need to put into each component that relies on user a call to useQuery that fetches the user. On initial page load, it's an extra, unnecessary network request since the LOG_IN already gets us the user data. But after the initial page load, if the user decides to log in or log out, then getting the user will be based on the update to the cache and having its updated user data be broadcasted to the useQuerys.

In this case, it's more ideal to use setUser if it means one less network request on initial page load. As always, it's completely up to you how you want to manage state in your applications, but be sure to evaluate the trade-offs for each possible solution and pick the one that best suits your situation.

Check out this Codesandbox example to see what I mean:

https://codesandbox.io/embed/mutations-example-app-final-tjoje?fontsize=14&hidenavigation=1&theme=dark

Next Steps#

If you want to learn more advanced techniques with TypeScript, GraphQL and React, or learn how to build a production-ready Airbnb-like application from scratch, then check out our TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL:

Clap
1|0