Search code examples
reactjstypescriptredux-toolkitrtk-query

How to get the query Key corresponding to the last query in the create Api RTK Q


In the RTK Query documentation https://redux-toolkit.js.org/rtk-query/usage/usage-without-react-hooks An example is given of performing a mutation without using react hooks Here is a fragment of it

import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { FullUser, Post, User } from "./types";
import { cacher } from "../rtkQueryCacheUtils";

export const api = createApi({
  baseQuery: fetchBaseQuery({
    baseUrl: "https://jsonplaceholder.typicode.com/"
  }),
  // global configuration for the api
  keepUnusedDataFor: 30,
  tagTypes: [...cacher.defaultTags, "User"],
  endpoints: (builder) => ({
    getUsers: builder.query<User[], number>({
      query: (count) => `users?_start=0&_end=${count}`,
      providesTags: cacher.providesList("User"),
      // configuration for an individual endpoint, overriding the api setting
      keepUnusedDataFor: 5,
      transformResponse: (response: FullUser[]) => {
        const simpleUsers: User[] = response.map(({ id, name }) => ({
          id,
          name
        }));
        return simpleUsers;
      }
    }),
    updateUser: builder.mutation<User, Partial<User> & Pick<User, "id">>({
      query: ({ id, ...patch }) => ({
        url: `posts/${id}`,
        method: "PUT",
        body: patch
      }),
      async onQueryStarted({ id, ...patch }, { dispatch, queryFulfilled }) {
        const { undo } = dispatch(
          api.util.updateQueryData("getUsers", 3, (draft) => {
            draft.forEach((user) => {
              if (user.id === id) {
                Object.assign(user, patch);
              }
            });
          })
        );

        try {
          await queryFulfilled;
        } catch (err) {
          console.log(err);
          undo();
        }
      }
    })
  })
});

export const { useGetUsersQuery, useUpdateUserMutation } = api;

In string

api.util.updateQueryData("getUsers", 3, (draft) => {

queryKey equal to 3.

Is there a way to get a query Key that will match the last endpoint request "getUsers"? In order to update the cache associated with the last request


Solution

  • I suspect that is a typo in the example snippet and should probably be the id variable that was destructured from the query argument passed to the updateUser endpoint's onQueryStarted method and is the query argument of the getUsers endpoint, e.g. count.

    Likely corrected example using the id to optimistically update the getUsers endpoint cache.

    async onQueryStarted({ id, ...patch }, { dispatch, queryFulfilled }) {
      const { undo } = dispatch(
        api.util.updateQueryData("getUsers", id, (draft) => {
          draft.forEach((user) => {
            if (user.id === id) {
              Object.assign(user, patch);
            }
          });
        })
      );
    
      try {
        await queryFulfilled;
      } catch (err) {
        console.log(err);
        undo();
      }
    }
    

    See onQueryStarted declaration:

    async function onQueryStarted(
      arg: QueryArg,
      {
        dispatch,
        getState,
        extra,
        requestId,
        queryFulfilled,
        getCacheEntry,
      }: MutationLifecycleApi,
    ): Promise<void>
    

    See also updateQueryData:

    const updateQueryData = (
      endpointName: string,
      args: any,
      updateRecipe: (draft: Draft<CachedState>) => void,
      updateProvided?: boolean,
    ) => ThunkAction<PatchCollection, PartialState, any, AnyAction>
    
    interface PatchCollection {
      patches: Patch[]
      inversePatches: Patch[]
      undo: () => void
    }
    

    The 3, or id, isn't the query key, it's simply the args argument passed to the query function.

    export type query = <QueryArg>(
      arg: QueryArg,
    ) => string | Record<string, unknown>
    

    Note also that this isn't a mechanism used to update the last getUsers endpoint, but to simply update the cache corresponding to the specified query arg. Order doesn't really matter, you are just updating the cache.