Blog>
Snippets

Performing Mutations with useMutation

Illustrate using the useMutation hook to perform create, update, and delete operations, and how to handle optimistic updates for a better user experience.
import { useMutation, useQueryClient } from 'react-query';
import axios from 'axios';

const useVoteMutation = () => {
  const queryClient = useQueryClient();
  return useMutation(vote => axios.post('/votes', vote), {
    // Optimistic Update
    onMutate: async newVote => {
      await queryClient.cancelQueries('votes');
      const previousVotes = queryClient.getQueryData('votes');
      queryClient.setQueryData('votes', old => [...old, newVote]);
      return { previousVotes };
    },
    onError: (error, newVote, context) => {
      queryClient.setQueryData('votes', context.previousVotes);
    },
    onSettled: () => {
      queryClient.invalidateQueries('votes');
    },
  });
};
This code defines a custom hook called useVoteMutation using React Query's useMutation hook. It performs an optimistic update for voting operation, where it immediately updates the local cache with the new vote before the mutation is confirmed by the server. If the mutation fails, the local data is rolled back to its previous state.
const { mutate, isLoading, error } = useVoteMutation();

// Function to call when casting a vote
const castVote = () => {
  mutate({ type: 'upvote', userId: '123' });
};
This code snippet demonstrates how to use the useVoteMutation hook. It shows how to perform a mutation by calling the mutate function, which would be to cast a vote in this example. It also shows how to access the isLoading and error states to manage UI feedback.
const deleteVoteMutation = useMutation(
  // Mutation function
  voteId => axios.delete(`/votes/${voteId}`),
  {
    // Optimistic update reverses
    onMutate: async deletedVoteId => {
      await queryClient.cancelQueries('votes');
      const previousVotes = queryClient.getQueryData('votes');
      queryClient.setQueryData('votes', old => old.filter(vote => vote.id !== deletedVoteId));
      return { previousVotes };
    },
    onError: (_, __, context) => {
      queryClient.setQueryData('votes', context.previousVotes);
    },
    onSettled: () => {
      queryClient.invalidateQueries('votes');
    },
  }
);
This code snippet demonstrates creating another mutation using useMutation for deleting a vote. Similar to the vote mutation, it employs an optimistic update strategy to immediately remove the vote from the local cache before verifying that the backend operation succeeded. If the delete operation fails, the vote is restored to its initial state.