Optimistic Updates with RTK Query
Tags: redux
Published: 2023-05-28 07:57:05

This is my memo from when I implemented optimistic updates with RTK Query.
Below is the final result of what I implemented. Both the “add to cart” and “add to wishlist” buttons send requests to the server to process these actions, the browser side acts like the client side manages these data.

![](https://cdn-images-1.medium.com/max/2000/1*n_2sPA1Xn4JZ763AYKtMmw.gif)

We can leverage [onQueryStarted](https://redux-toolkit.js.org/rtk-query/api/createApi#onquerystarted) to implement that feature. Here is an example of onQueryStarted usage.
```javascript
    async onQueryStarted({ cartItemToAdd }, { dispatch, queryFulfilled }) {
            const patchResult = dispatch(
              cartApi.util.updateQueryData("getCartItems", undefined, (draft) => {
                const updatedCartItems = addItemToCart(
                  draft.cartItems,
                  cartItemToAdd
                );
                return {
                  ...draft,
                  cartItems: updatedCartItems,
                };
              })
            );
            try {
              await queryFulfilled;
            } catch {
              patchResult.undo();
    }
```
## Trouble shooting

Here are some mistakes I make made during the development process.

* Error: TypeError: Cannot read properties of undefined (reading 'select')

If you got this error message you might pass a wrong query name at updateQueryData.

In my case, I misspelled getCarItems.
```javascript
    // Correct
    cartApi.util.updateQueryData("getCartItems", undefined, (draft) => {
                const updatedCartItems = addItemToCart(
                  draft.cartItems,
                  cartItemToAdd
                );
                return {
                  ...draft,
                  cartItems: updatedCartItems,
                };
              })
    // Wrong
    cartApi.util.updateQueryData("getCartItem", undefined, (draft) => {
                const updatedCartItems = addItemToCart(
                  draft.cartItems,
                  cartItemToAdd
                );
                return {
                  ...draft,
                  cartItems: updatedCartItems,
                };
              })
```
* Retune draft 
As long as I observe, it works without return when you directly modify the draft object like the example provided in the official document. Otherwise, you need to return the updated object.
```javascript
    // Works without return
    async onQueryStarted({ wishlist }, { dispatch, queryFulfilled }) {
            const patchResult = dispatch(
              wishlistApi.util.updateQueryData(
                "getWishlist",
                undefined,
                (draft) => {
                  draft.products = [...draft.products, wishlist];
                }
              )
            );
            try {
              await queryFulfilled;
            } catch {
              patchResult.undo();
            }
          },
```
```javascript
    // Work only with return
    cartApi.util.updateQueryData("getCartItems", undefined, (draft) => {
                const updatedCartItems = addItemToCart(
                  draft.cartItems,
                  cartItemToAdd
                );
                return {
                  ...draft,
                  cartItems: updatedCartItems,
                };
    })
```
ref:

[https://redux-toolkit.js.org/rtk-query/usage/manual-cache-updates#optimistic-updates](https://redux-toolkit.js.org/rtk-query/usage/manual-cache-updates#optimistic-updates)

original article is [here](https://medium.com/@lada496/optimistic-updates-with-rtk-query-4770698de6c1)