Implementing Optimistic Updates in TanStack Store
Present a code example that implements optimistic updates using TanStack Store, allowing the UI to update immediately before the server response is received to improve perceived performance.
import { useMutation } from 'tanstack/react-query';
// Assume we have a todos store and a function to update the todo in the backend
function updateTodoOnServer(todoId, newTodoData) {
// This represents your API call to the server
return fetch(`/api/todos/${todoId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(newTodoData),
}).then((res) => res.json());
}
This code snippet imports the `useMutation` hook from TanStack (specifically, the React Query library) and defines a function `updateTodoOnServer`, which simulates updating a todo item on the server via an API call using the Fetch API.
const { mutate } = useMutation(
({ todoId, newTodoData }) => updateTodoOnServer(todoId, newTodoData),
{
// onMutate is triggered before the mutation function is called
onMutate: async ({todoId, newTodoData}) => {
// Cancel any outgoing refetches
await queryClient.cancelMutations();
// Snapshot the previous value
const previousTodos = queryClient.getQueryData(['todos']);
// Optimistically update to the new value
queryClient.setQueryData(['todos'], (old) => ({
...old,
[todoId]: {...old[todoId], ...newTodoData},
}));
return { previousTodos };
},
// If the mutation fails, use the context returned from onMutate to rollback
onError: (err, variables, context) => {
queryClient.setQueryData(['todos'], context.previousTodos);
},
// Always refetch after error or success
onSettled: () => {
queryClient.invalidateQueries(['todos']);
},
}
);
This snippet demonstrates how to use the `mutate` function from the useMutation hook to perform optimistic updates. When `mutate` is called (e.g., after a user action), it updates the UI optimistically with `onMutate` by setting new data for the todo item directly in the cache before the server responds. If the update fails, the `onError` function rolls back to the previous state. After the mutation succeeds or fails, `onSettled` ensures the relevant data is refetched from the server.