Blog>
Snippets

Optimistic Updates with useMutation

Illustrate how to use the useMutation hook to perform optimistic updates, by temporarily updating the UI before the mutation's success confirmation from the server.
import { useMutation, useQueryClient } from 'react-query';
First, import useMutation and useQueryClient from react-query.
const updateTodo = async (todo) => {
  // API call to update the todo, replace URL with your API endpoint
  const response = await fetch('https://your-api/todos/' + todo.id, {
    method: 'PUT',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(todo),
  });
  return response.json();
};
Define the async function that will be used to send the updated todo to the server. This example uses the Fetch API to send a PUT request.
const useUpdateTodo = () => {
  const queryClient = useQueryClient();
  return useMutation(updateTodo, {
    onMutate: async (newTodo) => {
      // Cancel any outgoing refetches (so they don't overwrite our optimistic update)
      await queryClient.cancelQueries('todos');
      // Snapshot the previous value
      const previousTodos = queryClient.getQueryData('todos');
      // Optimistically update to the new value
      queryClient.setQueryData('todos', oldTodos => {
        return oldTodos.map(todo => todo.id === newTodo.id ? { ...todo, ...newTodo } : todo);
      });
      return { previousTodos };
    },
    onError: (err, newTodo, context) => {
      // Rollback to the previous value
      queryClient.setQueryData('todos', context.previousTodos);
    },
    onSettled: () => {
      // After mutation or error, refetch the todos query
      queryClient.invalidateQueries('todos');
    },
  });
};
Define a custom hook `useUpdateTodo` using the `useMutation` hook. This hook sets up optimistic updates for updating a todo. Before the mutation is sent to the server, it optimistically updates the UI. If the mutation fails, it rolls back the change.
const { mutate: updateTodo } = useUpdateTodo();
Use the custom hook `useUpdateTodo` in your component to get the mutate function. This function is used to trigger the mutation.
<button onClick={() => updateTodo({ id: todo.id, title: 'Updated Todo' })}>Update Todo</button>
Example of using the `updateTodo` mutate function on a button click event to update a todo's title. Replace `todo.id` and `'Updated Todo'` with your actual data.