Optimistic Updates
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 executedyou 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.
// file: types.ts noEmit
export interface Post {
id: number
name: string
}
// file: api.ts
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'],
// highlight-start
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()
}
},
// highlight-end
}),
}),
})
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
Last updated
Was this helpful?