Blog>
Snippets

Optimistic Updates for Snappier UI Experience

Explain how to implement optimistic updates with React Query by immediately updating the UI based on the expected response of a mutation, before receiving the actual response from the server.
import { useMutation, useQueryClient } from 'react-query';

const updatePost = async (postData) => {
  // Assume this function updates a post on the server and returns the updated post data
  return fetch('/api/posts/' + postData.id, {
    method: 'PUT',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(postData),
  }).then(res => res.json());
};
Defines a function 'updatePost' to perform the async operation, making an HTTP PUT request to update a post. This is the mutation operation that will be optimistically updated in the UI.
const useOptimisticUpdatePost = () => {
  const queryClient = useQueryClient();
  return useMutation(updatePost, {
    onMutate: async (newPost) => {
      await queryClient.cancelQueries('posts');
      const previousPosts = queryClient.getQueryData('posts');
      queryClient.setQueryData('posts', old => old.map(post => post.id === newPost.id ? { ...post, ...newPost } : post));
      return { previousPosts };
    },
    onError: (err, newPost, context) => {
      queryClient.setQueryData('posts', context.previousPosts);
    },
    onSettled: () => {
      queryClient.invalidateQueries('posts');
    },
  });
};
Creates a custom hook 'useOptimisticUpdatePost' that returns a mutation object from 'useMutation'. This object is set up to perform optimistic updates by: 1. Storing the current list of posts before mutation ('onMutate'). 2. Immediately updating the cache with the new post data. 3. On error, rolling back to the previous state of posts. 4. On mutation completion (whether success or failure), invalidating cached posts data to fetch the latest.
const PostUpdater = ({ postData }) => {
  const { mutate } = useOptimisticUpdatePost();
  return (
    <button onClick={() => mutate(postData)}>Update Post</button>
  );
};
Defines a React component 'PostUpdater' that uses the 'useOptimisticUpdatePost' hook. It renders a button that, when clicked, triggers the mutation along with the optimistic UI update.