-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
Right now the standard pattern for an optimistic update is pretty verbose:
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,
}),
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()
/**
* Alternatively, on failure you can invalidate the corresponding cache tags
* to trigger a re-fetch:
* dispatch(api.util.invalidateTags(['Post']))
*/
}
},
}),
}),
})
You have to:
- Implement
onQueryStarted
- Do
const patchResult = dispatch(api.util.updateQueryData(endpointName, arg, updateCb)
await queryFulfilled
- catch that and call
patchResult.undo()
We could add a new option and a new lifecycle API method to simplify this.
Conceptual idea:
type OptimisticUpdateDefinition {
endpointName: EndpointName;
arg: Arg;
update: (draft) => T
}
// then in a mutation endpoint:
applyOptimistic: (mutationArg: Arg, maybeSomeLifecycleApi: LifecycleApi) => (OptimisticUpdateDefinition | PatchCollection)[]
That way, the simple approach is to just list some endpoints you want updated, or you can import and reference another API slice to handle more complex cases where this API slice doesn't know about the endpoint:
applyOptimistic: (id) => [
// simple case
{endpointName: "todos", arg: id, update: (todos) => todos.push({id})},
// more complex
anotherApi.util.updateQueryData("otherTodos", id, (todos) => todos.push({id})
]
Internally, that would then convert the "simple" cases to PatchCollection
s as well, and then we could dispatch those, calling patchResult.undo()
if needed. We could even consider batching all of them into a single dispatch, and still revert the patches individually if needed.
We could also add a lifecycleApi.applyOptimistic()
helper that does the try/catch wrapping.
We could also also do the same thing for pessimistic updates.