How to Update React Query in React
This article provides a straightforward guide on how to update React Query (now known as TanStack Query) in your React applications. You will learn how to upgrade the library package to the latest version, handle breaking changes, and programmatically update your cached server state using mutations and query invalidation.
Upgrading the React Query Package
To update the React Query library itself, you need to use your project’s package manager.
Note that starting from version 4, the package was renamed from
react-query to @tanstack/react-query.
Step 1: Install the Latest Version
Run one of the following commands in your project terminal depending on your package manager:
# Using npm
npm install @tanstack/react-query@latest
# Using yarn
yarn add @tanstack/react-query@latest
# Using pnpm
pnpm add @tanstack/react-query@latestStep 2: Update Your Imports
If you are upgrading from version 3 to version 4 or 5, you must update your import statements across your project:
// Old import (v3 and below)
import { useQuery } from 'react-query';
// New import (v4 and above)
import { useQuery } from '@tanstack/react-query';Updating Data (State) in React Query
In React Query, “updating” usually refers to modifying server data and ensuring the local cache reflects those changes. This is achieved using mutations and query invalidation.
1. Perform Updates Using
useMutation
To send update requests to your API (like POST,
PUT, or DELETE), use the
useMutation hook.
import { useMutation, useQueryClient } from '@tanstack/react-query';
const updateTodo = async (todoId, updatedData) => {
const response = await fetch(`/api/todos/${todoId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(updatedData),
});
return response.json();
};2. Invalidate the Cache to Trigger a Refetch
After a successful mutation, the local cache becomes outdated. You
should invalidate the relevant query using
queryClient.invalidateQueries to force React Query to fetch
the fresh data.
export function EditTodoComponent({ todoId }) {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: (updatedData) => updateTodo(todoId, updatedData),
onSuccess: () => {
// Invalidate the 'todos' query list to trigger a refetch
queryClient.invalidateQueries({ queryKey: ['todos'] });
},
});
const handleUpdate = () => {
mutation.mutate({ title: 'New Todo Title' });
};
return <button onClick={handleUpdate}>Update Todo</button>;
}3. Update the Cache Manually (Optimistic Updates)
If you want to update the UI instantly before the server responds,
you can manually update the cache using
queryClient.setQueryData.
const mutation = useMutation({
mutationFn: updateTodo,
onMutate: async (newTodo) => {
// Cancel outgoing refetches so they don't overwrite our optimistic update
await queryClient.cancelQueries({ queryKey: ['todos'] });
// Snapshot the previous value
const previousTodos = queryClient.getQueryData(['todos']);
// Optimistically update to the new value
queryClient.setQueryData(['todos'], (old) => [...old, newTodo]);
// Return a context object with the snapshotted value
return { previousTodos };
},
onError: (err, newTodo, context) => {
// Rollback to the previous state if the mutation fails
queryClient.setQueryData(['todos'], context.previousTodos);
},
onSettled: () => {
// Always refetch after error or success to sync with the server
queryClient.invalidateQueries({ queryKey: ['todos'] });
},
});