20

Project uses redux toolkit and rtk query. Data are fetched from one api, but the code is split into smaller chunks to reflect logical parts like

  • /vehicles
  • /users
  • /settings

...etc

After logout rtk query preserves its state, so on next login the data are old. They might not even reflect the current user. How can I invalidate all the caches?

Dmitry Avgustis
  • 854
  • 1
  • 9
  • 14

3 Answers3

30

Actually it is pretty simple, but I had to refactor the code.

I created new api for each logical part. So to invalidate cache I would have to reset each api's state individually.

Fortunately rtk has code splitting capabilities in it.

https://redux-toolkit.js.org/rtk-query/usage/code-splitting

Basically you create baseApi likes this:

export const baseApi = createApi({
  baseQuery: fetchBaseQuery({
    baseUrl: `${BASE_URL}/api`,
    prepareHeaders: (headers, { getState }) => {
      const token = (getState() as RootState).auth.token;
      if (token) {
        headers.set("authorization", `Bearer ${token}`);
      }
      return headers;
    },
  }),
  tagTypes: ["Vehicle", "CompanySetting", "Associate"],
  endpoints: () => ({}),
});

Then you can add api slice to it in a separate file, like so

export const companySettingsApi = baseApi.injectEndpoints({
  endpoints: (builder) => ({
    getCompanySettings: builder.query<CompanySetting[], void>({
      query: () => ({
        url: `/companySettings`,
      }),
      providesTags: (_) => ["CompanySetting"],
    }),
    setCompanySettings: builder.mutation<void, CompanySetting[]>({
      query: (companySettings) => ({
        url: `/companySettings`,
        method: "PUT",
        body: companySettings,
      }),
      invalidatesTags: (_) => ["CompanySetting"],
    }),
  }),
});

This gives you ability to reset entire api state with a single dispatch

    dispatch(baseApi.util.resetApiState());
Dharman
  • 30,962
  • 25
  • 85
  • 135
Dmitry Avgustis
  • 854
  • 1
  • 9
  • 14
  • 3
    That is also one of the reasons why we are very adamant in the docs that you usually should just have one api ;) – phry Mar 22 '22 at 17:29
  • Also, please note that if you use redux-persist to persist api state that you also have to rehydrate it according to https://redux-toolkit.js.org/rtk-query/usage/persistence-and-rehydration – phry Mar 22 '22 at 17:30
  • Tags invalidation is not work because it not clears cache, so user dependent data still available after that, even after data refetch and receiving 4XX status code. `api.util.resetApiState` only can help, but it forces all cache data to be cleared. – Alex Shul Feb 26 '23 at 16:30
  • Thanks for this answer, I've been scratching my head around this for a while. – Anjaan Apr 18 '23 at 15:44
18

SOLUTION: This will immediately remove all existing cache entries, and all queries will be considered 'uninitialized'. So just put the below code into onClick or according to your scenario so when you hit an enter request will go and cache would also be clear. below here api is your name of an api which you would set in your rtk query in store.

dispatch(api.util.resetApiState());

For more info please have a look in documentation https://redux-toolkit.js.org/rtk-query/api/created-api/api-slice-utils

Jamal Ashraf
  • 569
  • 6
  • 9
  • so we need to do this for all API's we have ? – Bryan Lumbantobing Sep 08 '22 at 14:54
  • @BryanLumbantobing yes you need to do this for API’s for which you don’t want to store data in cache and everytime query will fetch results from an API. It depends on your usecase, sometimes we don’t need it. – Jamal Ashraf Sep 10 '22 at 07:11
11

In case you need to reset only specific cache, for example 'CompanySettings', you can also use:

dispatch(api.util.invalidateTags(['CompanySettings'])

Documentation https://redux-toolkit.js.org/rtk-query/api/created-api/api-slice-utils#invalidatetags

Kristjan
  • 139
  • 1
  • 8