Blog>
Snippets

Performing CRUD Operations with useMutation

Illustrate how to use the useMutation hook for creating, updating, and deleting data on the server, including how to manage optimistic updates.
import { useMutation, useQueryClient } from 'react-query';

const useCreateItem = () => {
  const queryClient = useQueryClient();
  return useMutation(createItem, {
    // On mutation success, invalidate cache to refetch
    onSuccess: () => {
      queryClient.invalidateQueries('items');
    },
    // Optimistically update the cache to include the new item
    onMutate: async (newItem) => {
      await queryClient.cancelQueries('items');
      const previousItems = queryClient.getQueryData('items');
      queryClient.setQueryData('items', (old) => [...old, newItem]);
      return { previousItems };
    },
    // Revert optimistic update if mutation fails
    onError: (err, newItem, context) => {
      queryClient.setQueryData('items', context.previousItems);
    },
  });
};
This snippet defines a custom hook `useCreateItem` that uses `useMutation` for creating a new item on the server. It optimistically updates the cache before the mutation is completed and reverts changes if the mutation fails.
const useUpdateItem = () => {
  const queryClient = useQueryClient();
  return useMutation(updateItem, {
    onSuccess: () => {
      queryClient.invalidateQueries('items');
    },
    onMutate: async (updatedItem) => {
      await queryClient.cancelQueries('items');
      const previousItems = queryClient.getQueryData('items');
      queryClient.setQueryData('items', (oldItems) => oldItems.map(item => item.id === updatedItem.id ? {...item, ...updatedItem} : item));
      return { previousItems };
    },
    onError: (err, newItem, context) => {
      queryClient.setQueryData('items', context.previousItems);
    },
  });
};
This code snippet creates a `useUpdateItem` hook that utilizes `useMutation` for updating an item on the server. It manages optimistic updates by immediately applying changes to the cache and reverting on failure.
const useDeleteItem = () => {
  const queryClient = useQueryClient();
  return useMutation(deleteItem, {
    onSuccess: () => {
      queryClient.invalidateQueries('items');
    },
    onMutate: async (itemId) => {
      await queryClient.cancelQueries('items');
      const previousItems = queryClient.getQueryData('items');
      queryClient.setQueryData('items', (oldItems) => oldItems.filter(item => item.id !== itemId));
      return { previousItems };
    },
    onError: (err, itemId, context) => {
      queryClient.setQueryData('items', context.previousItems);
    },
  });
};
This code illustrates the `useDeleteItem` hook which uses `useMutation` to delete an item on the server. It includes an optimistic update where the item is immediately removed from the cache, with a rollback mechanism in case of failure.