redux-toolkit: Optimistic updates not working on a graphql-based base query

I’m trying to implement optimistic updates on my graphql-based base query setup; however, after the mutation is triggered, the api.util.updateQueryData call seems not to be updating the cached data.

Here’s my endpoint:

import { createApi, retry } from '@reduxjs/toolkit/query/react';
import { gql } from 'graphql-request';
import { graphqlRequestBaseQuery } from '@rtk-query/graphql-request-base-query';

export const api = createApi({
  reducerPath: 'api',
  baseQuery: backedOffGraphqlBaseQuery,
  tagTypes: ['order', 'user', 'vehicle'],
  endpoints: (builder) => ({
    [...]
    transitionOrderStatus: builder.mutation<string, { status: OrderStatus; orderId: string }>({
      query: ({ status, orderId }) => ({
        document: gql`mutation transitionOrderStatus($status: OrderStatus!, $orderId: String!) {
    transitionOrderStatus(status: $status, orderId: $orderId)
  }`,
        variables: {
          status,
          orderId,
        },
      }),
      async onQueryStarted({ orderId }, { dispatch, queryFulfilled }) {
        const patchResult = dispatch(
          api.util.updateQueryData('getOpenOrders', orderId, (ordersDraft) => {
            const orders = ordersDraft.filter((o) => o.id !== orderId);
            ordersDraft = orders;
          }),
        );

        try {
          await queryFulfilled;
        } catch (error) {
          patchResult.undo();
        }
      },
      // invalidatesTags: ['order'],
    }),
    [...]

Any thoughts on why the dispatched api.util.updateQueryData action is not getting the cached data updated?

Thanks! By the way, I’m almost done migrating our production web app to RTK Query and I’m fascinated by it. Also, I’ve found the docs extremely educative and just FUN!

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 21 (16 by maintainers)

Most upvoted comments

So, the arg passed in to updateQueryData has to match those provided on the actual endpoint?

Yes, it has to match exactly. Ultimately, the reducer logic is doing something like state.api.queries[queryName + serializedQueryKey] to determine which data should be updated. You must provided the exact same cache key in order for it to find that cached value.

Just to add that bit of information: getState here cannot automatically have the right state type, as the api slice being created here would be a prerequisite to know that type - so the TS type here only contains the slice itself to not create a circular type reference. You would need to manually cast that to the correct type, as Mark already mentioned, by doing

const state = getState() as RootState;

I’m not sure where exactly that pointer to getState gets its state type from.

Worst case, you can import type { RootState } from 'app/store' to have the type accessible in this file, then do:

const state = getState() as RootState;
// access all fields on `state` here

assuming you’ve followed our standard TS setup guidelines:

https://redux.js.org/tutorials/typescript-quick-start

Your “slices” are adjacent to state.api, not inside of it. Try getState().otherSliceHere, etc.