Blog>
Snippets

Optimistic UI Updates with TanStack Router

Detail how to implement optimistic UI updates in a data mutation scenario, including handling potential errors and reverting the UI to its previous state if the update fails.
import { useMutation, useQueryClient } from 'react-query';
First, import `useMutation` and `useQueryClient` from react-query to handle the mutation and to access the query client for cache updates.
const updateData = async (newData) => {
  // Replace with your update logic, typically an API call
  return fetch('/api/data', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(newData),
  }).then(res => res.json());
};
Define the `updateData` function which makes an API call to update your data. This function should return a promise with the updated data.
const useOptimisticUpdate = () => {
  const queryClient = useQueryClient();

  return useMutation(updateData, {
    onMutate: async (newData) => {
      await queryClient.cancelQueries('data');

      const previousData = queryClient.getQueryData('data');
      queryClient.setQueryData('data', newData);

      return { previousData };
    },
    onError: (err, newData, context) => {
      queryClient.setQueryData('data', context.previousData);
    },
    onSettled: () => {
      queryClient.invalidateQueries('data');
    }
  });
};
Define a custom hook `useOptimisticUpdate` using `useMutation` to perform the update. This hook temporarily updates the query cache optimistically, rolls back on error, and finally, refetches the data for consistency.
const { mutate } = useOptimisticUpdate();

// Call this function with the new data to update optimistically
mutate(newData);
Use the `useOptimisticUpdate` hook to get the `mutate` function, which you can then call with the new data to perform an optimistic UI update.