Fetching data from the server and maintaining it is a very crucial issue in the frontend development. In this article we will focus on the React.js library applications and how we maintain the server state with the library called React-Query.
Into React-Query
In React, there are three types of state: the local state, which is persisted in the React components; the global state, all components can access to it; and the server state which is persisted in the server most of the time and depends on both sides. To manage the server state in the frontend and sync with the backend, we need to update, cache or re-fetch the data efficiently. Sometimes we call the backend more than necessary, and this could cause performance problems in our applications. There, the React-query library helps us to solve these performance issues, manage the cache properly and give us useful features like query cancellation, stale time configuration, infinite query refetching etc.
React Query is a library that has 2 simple hooks which provide fetching, caching and updating asynchronous data in React applications. It was created by open sourcerer Tanner Linsley in 2019, and now it is proven that it is very useful in server state management in React applications. There are also other libraries like SWR, Apollo Client and RTK-Query for the server state management and we can see their comparison with React query in their webpage: https://react-query.tanstack.com/comparison. According to react-query page comparison, react-query is the best option objectively.
Benefits of using React-Query
Some of the advantages that brings us React-Query are:
- Configuring the stale, cache, retry delay time creating a queryClientConfig object.
- Updating the stale data in the background since react-query prefetches.
- Optimizing the requests to the backend.
- With the refetchOnWindowFocus feature, it can refetch in the background when the user changes the browser tab or when they come back to the app.
And there are more of them that we will specify later.
What are the stale and cache time in the terms of React-query? Maybe we can start with explaining the five query states that React-query has in its development cycle and also which we will encounter in React-Query Dev Tools.
Fresh: This state is when we have the almost same data on both sides (since when we received data, possible that someone is updated at the same time) and there is no need to refetch it.
Fetching: When we initially fetch the data successfully or not.
Stale: Out of date data which we will need to re-fetch it from the backend.
Inactive: This state is used to improve the speed/UX of our applications. It is previous to the deleted state.
The last state is the deleted state. After the data is inactive for a while (you can configure the time) it deletes from the cache.
After understanding the state of the queries we can explain the stale time and cache time. StaleTime is the duration of the transition from fresh to stale state. If we are in the fresh state we will get the data from the cache only, but if we are in the stale state we may do a background fetch. CacheTime is the duration until inactive queries will be removed from the cache. We can configure it by passing to a QueryClientProvider component from the library or passing locally in the useQuery call.
The two hooks that the library provides us are useQuery and useMutation. useQuery is used to fetch data and useMutation is used for creating, deleting and updating the data in the server. The useQuery takes a key, a function to call the api and one object to configure this call. And all the queries will be stored in the QueryCache.
const { data: questions = {}, isLoading}} = useQuery("questions",getQuestions,{staleTime:5000,cacheTime:10});
In addition to that you can send dynamic parameters in useQuery, and it will call the service when they change. For example in the code below, when “vendors” changes in the component, it will call the service again.
export const useFetchQuestions = (vendors: Array<string>,element: number) =>
useQuery([vendors], () => FormService.getDynamicQuestions(vendors, element));
The useMutation will take a mutation function to a service as required, but the mutation key will be optional. All the mutations will be stored in the MutationCache. And when we need to interact with QueryCache and MutationCache we will need to access firstly to QueryClient.
export const useDownloadFile = (filePath: string, fileId: number) =>
useMutation(() => FormService.downloadFile(filePath, fileId));
Conclusion
React query is a great tool to use in React applications to manage the server state, lazy loading, pagination and the cache maintenance. It has a simple approach and implementation. With its devtools support, it is clear to use also in more complex applications. After working with the projects which includes
React/Redux where all the state is in local, React-Query saves so much boilerplate code and synchronizes local state with server. I hope that this article can help to resume what React-Query can contribute to your projects. And for more advanced topics, I highly recommend you to have a look at this blog: https://tkdodo.eu/blog/practical-react-query which is written by one of the biggest collaborators of this library and his articles can be a great help.
Links of interest
Data fetching in Redux is painful, get rid of it now by Davide Cantelli @Medium
Why I Stopped Using Redux by Gabriel Abud @Dev.to
React Query – An Underrated State Management Tool by Tharaka Romesh @Bits and Pieces
React state management in 2022 – Return of the Redux by Kolby Sisk @Udacity
Comparison | React Query vs SWR vs Apollo vs RTK Query @React Query
RTK Query Comparision @Redux Toolkit
RTK Query: The future of data fetching and caching for Redux by Dylan Tientcheu @LogRocket
How and Why You Should Use React Query by Nathan Sebhastian @Bits and Pieces
Getting Started with React-Query for Data Fetching and State Management by Kevin Kimani @Section
React Query and management of server state by Nicolas Santos @Dev.to