Getting Started with React Query
Author: Joanna Piecuch
The problem
Each of us was once at the beginning of a project and wondered how to manage asynchronous data in an application. You probably know how annoying it could be to handle different states (loading, error), share data between components and keep the synchronized state in your components. So, let's overview React Query.
React Query - what is it?
React Query is a data management library. It makes fetching, caching, synchronizing and updating server state in your app.
Preparing React Query For Using
First we have to wrap our app with the provider.
const queryClient = new QueryClient();
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</React.StrictMode>
);
Fetching data
In the example below fetchCharacters is async method return an array with all characters.
React Query provides us the useQuery hook to fetch and control state of data.
export const Characters = () => {
const { isLoading, isError, data, error } = useQuery(['characters'],() => fetchCharacters());
}
The useQuery hook result contains some states, which can helpful to manage our app.
isLoadingwill be true when there is no data yet;datawill give us a result of async call;isErrorwill be true when async call returned an error;errorcontains error message;
Pagination and infinity scroll
If we have very long list of elements, will be better use the pagination. We can do it in two ways.
- The first way is basic pagination. We pass a page parameter to our call API method.
useQueryhook reacts on page changes.
export const Characters = () => {
const [page, setPage] = useState(1);
const { data, isLoading } = useQuery(['characters'], () =>
fetchCharacters(page)
);
}
- React Query provides us
useInfiniteQueryhook which contains some methods to handle pagination in easy way.
fetchNextPagemethods to fetch next page;hasNextPagewill be true when there is next page;isFetchingNextPagewill be true when fetching data a new page
export const CharactersInfinityScroll = () => {
const { data, fetchNextPage, hasNextPage, isFetchingNextPage } =
useInfiniteQuery(
['character-infinity'],
({ pageParam = 1 }) => fetchCharactersInfinity(pageParam),
{
getNextPageParam: (lastPage, allPages) => allPages.length + 1
}
);
}
Modifying data in the server
The second integral part to working with data is updating it. For this use-case, React Query provides us useMutation hook.
useMutation is similar to useQuery. It tracks state of mutations and give us a loading and error status.
In the example below addCharacter is a async method to add new character to the list. Mutations update data in the server, but if we want to synchronize data in the app,
we need to tell React Query: 'Hey, your data is invalid'. We can do it using invalidateQueries function. After that React Query automatically refetch data and update list.
export const CharacterUpdate = () => {
const { characterId } = useParams();
const addNewCharacter = useMutation((newCharacter: Character) =>
addCharacter(newCharacter, characterId),
{
onSuccess: () => {
queryClient.invalidateQueries(['characters'])
}
}
);
const onSubmit = (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
const inputValue = new FormData(event.currentTarget).get('name');
addNewCharacter.mutate(inputValue);
};
return (
<form onSubmit={onSubmit}>
<input name="name" placeholder="Character name" />
<button type="submit">Add new character</button>
</form>
);
};
Devtools
React Query has a great devtools feature. It is separate package that you need to install:
npm i @tanstack/react-query-devtools
and then we have to add React Query Devtools to our app.
const queryClient = new QueryClient();
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<ReactQueryDevtools initialIsOpen={false} />
<App />
</QueryClientProvider>
</React.StrictMode>
);
Conclusion
React Query is a good server state management library to simplifying your data-fetching needs. It provides many features which save our time and help to keep clean and simply code. React Query as every solution has pros and cons.
Pros and cons of solution
Pros:
- provides features like caching, loading and error handling out of the box;
- easy way to fetch data and pagination;
- request retry, we can set the number of request retries in the event of errors;
- devtools feature: view the cache in realtime, manually refetch and remove queries;
Cons:
- don't handle client state;
- might be not the best to use in situation when data is needed to another request;