Blog>
Snippets

Synchronizing optimistic updates across components

Explain how to keep the application state consistent across different components after performing optimistic updates using React Query's query invalidation features.
import { useMutation, useQueryClient } from 'react-query';

const updateUserProfile = async (userData) => {
  // Simulate a PATCH request to update user data on the server
  return fetch('/api/user', {
    method: 'PATCH',
    body: JSON.stringify(userData),
    headers: { 'Content-Type': 'application/json' },
  }).then(res => res.json());
};
This code defines an asynchronous function `updateUserProfile` to update user data on the server by making a PATCH request. It leverages the fetch API for making HTTP requests.
const useOptimisticUpdateUser = () => {
  const queryClient = useQueryClient();

  return useMutation(updateUserProfile, {
    onMutate: async (newData) => {
      await queryClient.cancelQueries('user');
      const previousUserData = queryClient.getQueryData('user');
      queryClient.setQueryData('user', prev => ({ ...prev, ...newData }));
      return { previousUserData };
    },
    onError: (err, newData, context) => {
      queryClient.setQueryData('user', context.previousUserData);
    },
    onSettled: () => {
      queryClient.invalidateQueries('user');
    },
  });
}
This hook `useOptimisticUpdateUser` uses React Query's `useMutation` to optimistically update user data across components. `onMutate` saves the previous state, optimistically updates the cache with the new data, and `onError` rolls back to the previous state in case of an error. After the mutation is settled, the `queryClient.invalidateQueries('user')` ensures all components using this query refetch their data to stay synchronized.