Search code examples
reactjstypescriptreduxredux-toolkitrtk-query

How to reset the values of `data` `isLoading` and `error` returned from hook in RTK query in a react typescript application?


I'm trying to query data from an end point with different params based on button click event.

I used the code splitting method by rtk query and created the base service as

import { createApi } from "@reduxjs/toolkit/query/react";
import { axiosBaseQuery } from "./util";

export const appApi = createApi({
  baseQuery: axiosBaseQuery({
    baseUrl: `https://baseurl`,
  }),
  refetchOnReconnect: true,
  endpoints: () => ({}),
});

and inject endpoint like

import { appApi } from "./appApi";

export const popupAPI = appApi.injectEndpoints({
  endpoints: (builder) => ({
    getPopupData: builder.query<
      any,
      {
        id: string;
        startDate: string | Date | null;
        endDate: string | Date | null;
      }
    >({
      query: (params) => {
        const { id, startDate, endDate } = params;
        return {
          url: `kpi/?id=${id}&startdate=${startDate}&enddate=${endDate}`,
        };
      },
    }),
  }),
  overrideExisting: true,
});

export const { useGetPopupDataQuery } = popupAPI;

In the component file the start date is set initially and changes on button click.

const startDate = moment()
  .subtract(selectedDays || 1, "days")
  .format("YYYY-MM-DD");
const endDate = moment()
  .subtract(1, "days")
  .format("YYYY-MM-DD");

The selectedDays is initially set to 1 and changes to 2, 3, etc on button click. I subscribe to the data and other variables like

const {
  data,
  isLoading,
  error,
} = useGetPopupDataQuery({
  id
  startDate: startDate,
  endDate: endDate,
});

On the first time, when component mounts the values of isLoading, data and error are set accordingly and when the data fetch completed the isLoading is set to false and data with data. But the issue is when I click the button the selectedDays changes and an API call is send. But the previous data isLoading error are not changed/reset. So I'm not able to show the loading/intermediate stage. The after the data fetch completes when inspected the data variable is filled with new data. I'm trying to resolve this issue and any help/suggestions would be really helpful.


Solution

  • The isLoading flag is used when the query is being initially made and there are no previous requests cached in the store. You might be looking to use the isFetching flag instead of, or in addition to, isLoading. The data will simply be the cached data from the previous successful request.

    See useQuery

    type UseQueryResult<T> = {
      // Base query state
      ...
    
      // Derived request status booleans
      isUninitialized: boolean // Query has not started yet.
      isLoading: boolean // Query is currently loading for the first time. No data yet.
      isFetching: boolean // Query is currently fetching, but might have data from an earlier request.
      isSuccess: boolean // Query has data from a successful load.
      isError: boolean // Query is currently in an "error" state.
    
      refetch: () => void // A function to force refetch the query
    }
    

    Here's an example I use for handling subsequent requests.

    const {
      data,
      isLoading as popupDataIsLoading,
      isFetching as pPopupDataIsFetching,
      error,
    } = useGetPopupDataQuery({
      id
      startDate: startDate,
      endDate: endDate,
    });
    
    const isLoading = popupDataIsLoading || pPopupDataIsFetching;
    

    Here you can apply any conditional logic when the query is either being loaded for the first time or an active request is pending.

    I wouldn't recommend it, but if you are looking for a "nuclear" option then there also exists resetApiState.

    Signature

    const resetApiState = () => ({
      type: string,
      payload: undefined,
    })
    

    Description A Redux action creator that can be dispatched to manually reset the api state completely. This will immediately remove all existing cache entries, and all queries will be considered 'uninitialized'.

    Note that hooks also track state in local component state and might not fully be reset by resetApiState.

    Example

    dispatch(api.util.resetApiState())
    

    This resets the entire API state and may very likely be too blunt a tool though. Use with caution.