'Optimistic updates for item create in RTK Query

Can't figure out how to get optimistic updates to work properly when I'm creating a new item rather than updating the existing one.

The optimistic updates do work but if I switch to Offline mode, the patchResult.undo() isn't removing the added element.

It would also be nice to have an example of deleting items optimistically

Here is my code

        createMessagesItem: builder.mutation<void, Omit<IMessagesItem, '_id'>>({
            query: (payload) => ({
                url: `messages`,
                method: 'POST',
                body: payload,
            }),

            async onQueryStarted(patch, { dispatch, queryFulfilled }) {
                const patchResult = dispatch(
                    storageApi.util.updateQueryData('getMessages', undefined, (draft) => {
                        draft.push({ ...patch, _id: '' });
                    })
                );

                try {
                    await queryFulfilled;
                } catch {
                    patchResult.undo();
                }
            },

            invalidatesTags: ['Messages'],
        }),


Solution 1:[1]

I think there are few error in your code, but can't reproduce for test the "offline" situation.

The main one is that this

draft.push({ ...patch, _id: '' });

should throw an error:

Property 'push' does not exist on type 'MaybeDrafted'. Property 'push' does not exist on type 'Post'

meaning draft is NOT an array BUT and Object thus you need to

Object.assign(draft, patch) 

in order to change draft attributes accordingly to patch.

Why not go as from the standard implementation as in docs:

updatePost: build.mutation<void, Pick<IMessagesItem, 'id'> & Partial<Post>>({
  query: ({ id, ...patch }) => ({
    url: `posts/${id}`,
    method: 'PUT',
    body: patch,
  }),
  async onQueryStarted({ id, ...patch }, { dispatch, queryFulfilled }) {
    const patchResult = dispatch(
      api.util.updateQueryData('getMessage', id, (draft) => {
        Object.assign(draft, patch)
      })
    )
    try {
      await queryFulfilled
    } catch {
      patchResult.undo()
    }
  },
  invalidatesTags: (result, error, { id }) => [{ type: 'Post', id }],
}),

this should be the delete query:

deletePost: build.mutation<{ success: boolean; id: number }, number>({
  query(id) {
    return {
      url: `posts/${id}`,
      method: 'DELETE',
    }
  },
  invalidatesTags: (result, error, id) => [{ type: 'IMessagesItem', id }],
}),

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1