Skip to main content

Optimistic Updates

When you're performing an update on some data that already exists in the cache via useMutation, RTK Query gives you a few tools to implement an optimistic update. This can be a useful pattern for when you want to give the user the impression that their changes are immediate.

The core concepts are:

  • when you start a query or mutation, onQueryStarted will be executed
  • you manually update the cached data by dispatching api.util.updateQueryData
  • then, in the case that promiseResult rejects, you roll it back via the .undo property of the object you got back from the earlier dispatch.
Optimistic update mutation example (async await)
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'import { Post } from './types'
const api = createApi({  baseQuery: fetchBaseQuery({    baseUrl: '/',  }),  tagTypes: ['Post'],  endpoints: (build) => ({    getPost: build.query<Post, number>({      query: (id) => `post/${id}`,      providesTags: ['Post'],    }),    updatePost: build.mutation<void, Pick<Post, 'id'> & Partial<Post>>({      query: ({ id, ...patch }) => ({        url: `post/${id}`,        method: 'PATCH',        body: patch,      }),      invalidatesTags: ['Post'],      async onQueryStarted({ id, ...patch }, { dispatch, queryFulfilled }) {        const patchResult = dispatch(          api.util.updateQueryData('getPost', id, (draft) => {            Object.assign(draft, patch)          })        )        try {          await queryFulfilled        } catch {          patchResult.undo()        }      },    }),  }),})

or, if you prefer the slightly shorter version with .catch

-      async onQueryStarted({ id, ...patch }, { dispatch, queryFulfilled }) {+      onQueryStarted({ id, ...patch }, { dispatch, queryFulfilled }) {        const patchResult = dispatch(          api.util.updateQueryData('getPost', id, (draft) => {            Object.assign(draft, patch)          })        )-       try {-         await queryFulfilled-       } catch {-         patchResult.undo()-       }+       queryFulfilled.catch(patchResult.undo)      }

Example#

View Example