Intro To Optimizing React Application Performance using React Apollo Client
Diving into solutions around React performance optimization can be a dizzying topic. I’d like to address optimizing application performance based on specific use cases to control and reduce expensive client network requests, using the solutions offered by the React Apollo Client library.
From its documentation, Apollo optimizations currently address:
- State management of local and remote data with GraphQL
- Querying application data
- Modifying application data
- Caching data
One valuable aspect that I appreciate about Apollo Client compared to other client HTTP libraries like Axios, is increased control over how applications handle network requests. Let’s address 3 approaches to optimizing client side requests (please note, this is not a comprehensive list of Apollo features):
- Dynamic and granular fetch operations with useQuery
- Component event listeners and useLazyQuery
- Fine tuned client caching with fetchPolicy
Imagine you have a component that needs to query a very expensive network request in order to render the correct data. Ideally, you may only want the component to re-fetch that data if:
Case 1: The request itself has changed
Case 2: The user has initiated some action
Case 3: The data response has changed
If you’re a front end engineer, you’ve run into this problem. Here are some ways to use Apollo to address optimization.
Case 1: If a fetch should only occur when a request has changed, try a useQuery with a skip variable. Apollo allows us to listen for variable updates within our component that can be passed as arguments to update the body, headers, query parameters, etc. in our request. As well, a skip variable to dictate conditional fetching.
Ex: Here we can dynamically pass the name state value to our FETCH_ADDRESS query. Also, a skip variable allows us to skip the fetch if the name doesn’t exist, reducing unnecessary requests.
Case 2: If a fetch does not need to occur every time the component mounts, and is only needed based on an event, or user interaction, try a useLazyQuery.
Ex: The useLazyQuery here will only fetch based on an onClick event, which passes a dynamic language variable to getGreeting. Apollo conveniently gives us a called, or loading variable to conditionally render components based on if the fetch has been made, or if data is still loading. This can help reduce unnecessary component renders.
Case 3: If a fetch only needs to occur if something in the response data has changed, try implementing a fetchPolicy. By default, the useQuery hook checks the Apollo Client cache to see if data you requested is already available locally. If all data is available locally, useQuery returns that data and doesn't query your GraphQL server. There are a variety of fetch policies to support the right cache operations. Other fetch Policies include:
fetchPolicy: "cache-first"; // default
Ex: Using a cache-first fetch policy, the GET_DOGS query will use data from the application cache first. If the response doesn’t exist or is expired, then it fetches a response from the network.
This article only suggests a few of the options available at the component level for Apollo fetch queries. Read more here.