React Query has been a game-changer for managing server-state in React applications, and with the release of version 5, it’s now even more powerful and user-friendly. If you’re considering migrating your project from React Query v4 to v5, you’re in the right place. This guide will walk you through the process step by step, highlighting the key changes and providing code snippets for an effortless transition.
Introduction to React Query v5
React Query v5 is here, and it’s packed with exciting new features and improvements. This version focuses on streamlining APIs and making it even more intuitive to use. Here are some of the highlights:
- Simplified Optimistic Updates: Performing optimistic updates is now easier than ever. Leverage returned
variables
fromuseMutation
without manual cache updates. - Infinite Queries with maxPages: Infinite queries can now have a maximum number of pages to store and refetch.
- Infinite Queries Prefetch Multiple Pages: Infinite Queries can prefetch multiple pages, enhancing performance.
- Fine-Grained Storage Persister: An experimental feature for fine-grained storage persistence has been added.
- Typesafe Query Options: Create query options in a typesafe way for improved development experience.
- New Hooks for Suspense: Dedicated hooks for handling suspense for data fetching have been introduced.
These additions, along with several improvements make v5 a compelling upgrade. However, they are breaking changes to be aware of.
Breaking Changes
Hooks now have a Single Signature
In v5, React Query now supports a single signature format using objects for passing options. Here’s a quick comparison:
Version 4:
// all of these signatures were acceptable in v4
useQuery(key, fn, options)
useQuery({ queryKey, queryFn, ...options })
useMutation(QUERY_FN);
useMutation({ mutationFn: QUERY_FN });
const queryClient = useQueryClient();
queryClient.refetchQueries(QUERY_KEY);
queryClient.refetchQueries({ queryKey: QUERY_KEY });
queryClient.fetchQuery(QUERY_KEY, QUERY_FN);
queryClient.fetchQuery({ queryKey: QUERY_KEY, queryFn: QUERY_FN });
Version 5:
// useQuery(key, fn, options) <no longer works!>
// Only the signature passing an object is acceptable
useQuery({ queryKey, queryFn, ...options })
// useMutation(QUERY_FN); <no longer works!>
useMutation({ mutationFn: QUERY_FN });
const queryClient = useQueryClient();
// queryClient.refetchQueries(QUERY_KEY); <no longer works!>
queryClient.refetchQueries({ queryKey: QUERY_KEY });
// queryClient.fetchQuery(QUERY_KEY, QUERY_FN); <no longer works!>
queryClient.fetchQuery({ queryKey: QUERY_KEY, queryFn: QUERY_FN });
Now, you simply just pass one object. This change simplifies the way you interact with queries, providing a more consistent API.
Callbacks on useQuery Removed
In v5, onSuccess
, onError
, and onSettled
callbacks have been removed from queries. However, they are still available for mutations. Make sure to update your code accordingly.
Version 4:
const query = useQuery(key, fn, {
onSuccess: handleSuccess,
onError: handleError,
onSettled: handleSettled,
});
Version 5:
const { data, error, status } = useQuery({ queryKey, queryFn });
if (error) {
return <p>error.message<p>
}
// OR
if (status == 'error') {
return <p>error.message<p>
}
useQuery
still returns an object containing the booleans isError
, isSuccess
and isPending
which can be used to conditionally render your view.
RefetchInterval Callback Function Change
The refetchInterval
callback function now only receives the query as a parameter. This streamlines how callbacks are invoked.
Version 4:
refetchInterval: (data, query) => ...
Version 5:
refetchInterval: (query) => ...
These are just a few of the significant changes in v5. Be sure to review the complete list of breaking changes in the migration guide for a comprehensive understanding.
Other Changes:
- Infinite queries now require
initialPageParam
- Hydrate has been renamed to
HydrationBoundary
. Also,useHydrate
hook has been removed - The
remove
method has been removed from useQuery cacheTime
renamed togcTime
- The status
loading
has been changed topending
andisLoading
has been changed toisPending
This is not an exhaustive list. You can view all the changes on React Query’s official migration guide.
Migrating to React Query v5: A Step-by-Step Guide
Now that we have an overview of the changes, let’s walk through the migration process step by step. We’ll provide code snippets comparing v4 and v5 to help you make a smooth transition.
Note: The minimum required version for TypeScript is now 4.7 and the minimum required React version is now 18.0
Step 1: Install React Query v5
Assuming you are using npm
, you can use the command below to install the latest version of React Query, which is version 5.4.3 at the time of writing this article.
npm i @tanstack/react-query@latest
Optional: React Query Devtools also received an update. To install the latest version use:
npm i @tanstack/react-query-devtools@latest
Step 2: Fix Breaking Changes
You can fix all the breaking changes manually by going file by file (the section before should help). Or, you can use a codemod to automatically update your codebase.
Codemod for Migration
To facilitate the migration process, a codemod is provided. It automates much of the migration, but it’s essential to review the generated code for edge cases. You can run the codemod using the following commands:
# For .js or .jsx files
npx jscodeshift ./path/to/src/ \
--extensions=js,jsx \
--transform=./node_modules/@tanstack/react-query/build/codemods/src/v5/remove-overloads/remove-overloads.js
# For .ts or .tsx files
npx jscodeshift ./path/to/src/ \
--extensions=ts,tsx \
--parser=tsx \
--transform=./node_modules/@tanstack/react-query/build/codemods/src/v5/remove-overloads/remove-overloads.js
Always remember to run prettier
and/or eslint
after applying the codemod to ensure code formatting consistency.
New Features in v5
Now that you have version 5 and fixed all the breaking changes, here are some of the new features you might find useful.
Simplified Optimistic Updates
Performing optimistic updates is now more straightforward.
const { mutate, isPending, variables } = useMutation({
mutationFn: (newTodo) => axios.post('/api/data', { text: newTodo }),
onSettled: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
});
return (
<div>
// variables is the mutated data
{ isPending && <p>{ variables }</p>}
<button onClick={() => mutate("Shopping")} style={{ marginLeft: 15 }}>
Add todo "Shopping"
</button>
</div>
);
Infinite Queries with maxPages
To boost site performance, limit the number of stored and refetched pages for infinite queries using the maxPages
option. This helps control memory usage while still allowing users to load content efficiently.
useInfiniteQuery({
queryKey,
queryFn: ({ pageParam }) => fetchSomething(pageParam),
initialPageParam: 0,
maxPages: 5, // Example limit
getNextPageParam: (lastPage) => lastPage.next,
});
Infinite Queries Prefetch Multiple Pages
Infinite Queries can now prefetch multiple pages, improving performance.
useInfiniteQuery({
queryKey,
queryFn: ({ pageParam }) => fetchSomething(pageParam),
initialPageParam: 0,
prefetchPages: 2, // Example prefetching 2 pages ahead
});
New Hooks for Suspense
You can use React Query with React’s Suspense to fetch data. Now, there are specific hooks like useSuspenseQuery
, useSuspenseInfiniteQuery
, and useSuspenseQueries
for this. These hooks ensure that data won’t be potentially undefined
on type level, and you won’t need status states or error objects. Instead, you’ll use the React.Suspense
component. To learn more, visit here.
import {
useSuspenseInfiniteQuery,
useSuspenseQueries,
useSuspenseQuery,
} from "@tanstack/react-query";
export const Suspense = () => {
const { data } = useSuspenseQuery({ queryKey: ['todos'], queryFn: () => {} });
const { data } = useSuspenseInfiniteQuery({
queryKey: ['todos'],
queryFn: () => {},
getNextPageParam: (lastPage) => lastpage.next,
initialPageParam: 1,
});
const { data } = useSuspenseQueries({
queries: [{ queryKey: ['todos'], queryFn: () => {} }],
});
};
New React Query DevTools v5
React Query Devtools got a cool UI update. Here is a sneak peak:
Conclusion
Migrating to React Query v5 opens up a world of new possibilities and streamlines the development experience. While there are breaking changes, the benefits far outweigh the effort required to make the transition. Take your time, review the migration guide, and leverage the provided codemod to make the process as smooth as possible.