Blog>
Snippets

Syncing Local and Server State with Optimistic Updates

Explain how to implement optimistic updates in React Query, allowing UI changes to reflect immediately before confirming changes on the server-side, and reverting if an error occurs.
import { useMutation, useQueryClient } from 'react-query';

const updateSection = async (sectionData) => {
  // Here you would make your API call to update the section
  return fetch('/api/section/update', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(sectionData),
  }).then((res) => res.json());
};
This code defines an asynchronous function to update a section. It uses the Fetch API to send a POST request to the server. Replace '/api/section/update' with your actual endpoint.
const useOptimisticUpdateSection = () => {
  const queryClient = useQueryClient();
  return useMutation(updateSection, {
    onMutate: async (newSection) => {
      await queryClient.cancelQueries('sections');
      const previousSections = queryClient.getQueryData('sections');
      queryClient.setQueryData('sections', (old) => [...old, newSection]);
      return { previousSections };
    },
    onError: (err, newSection, context) => {
      queryClient.setQueryData('sections', context.previousSections);
    },
    onSettled: () => {
      queryClient.invalidateQueries('sections');
    },
  });
};
This custom hook uses React Query's useMutation along with an optimistic update pattern: - onSave: Cancel ongoing fetches for sections and get the previous state. Temporarily update the state with the new section data optimistically before the mutation is confirmed. - onError: If the mutation fails, rollback to the previous sections state. - onSettled: After the mutation is either successful or unsuccessful, refetch the sections data to ensure it’s synchronized with the server.