Search code examples
reactjsreact-reduxrtk-query

React Redux Toolkit query not caching data


I'm using @reduxjs/toolkit/query to fetch data from my API in a React application. I'm using the useQuery hook to perform the query, but the data is not being cached as expected.

Here is my code:

// Define the API using createApi
export const defaultApi = createApi({
  reducerPath: 'defaultApi',
  baseQuery: fetchBaseQuery({
    baseUrl: process.env.REACT_APP_API_URL,
    prepareHeaders: (headers, { getState }) => {
      const {
        auth: { accessToken }
      } = getState() as any
      if (accessToken) {
        headers.set('Authorization', `Bearer ${accessToken}`)
      }
      return headers
    }
  }),
  endpoints: (builder) => ({
    products: builder.query<Product[], void>({
      query: () => {
        return {
          url: `/api/user/products`,
          providesTags: ['products'],
        }
      }
    })
  }),
})

My store:

import { AnyAction, configureStore, ThunkDispatch } from "@reduxjs/toolkit";
import { defaultApi } from "apis/default";
import { useDispatch } from "react-redux";
import {
  createMigrate,
  FLUSH,
  PAUSE,
  PERSIST, PersistedState, persistReducer,
  persistStore,
  PURGE,
  REGISTER,
  REHYDRATE
} from "redux-persist";
import storage from "redux-persist/lib/storage";
import rootReducer from "./rootReducer";

const migrations = {
  0: (state: PersistedState) => {
    return {
      _persist: {
        rehydrated: true,
        version: state?._persist?.version ?? 0,
      },
    };
  },
};

const persistConfig = {
  key: "primary",
  version: 15,
  storage,
  migrate: createMigrate(migrations, { debug: false }),
  whitelist: [
    "auth",
  ],
};

const persistedReducer = persistReducer(persistConfig, rootReducer);

const store = configureStore({
  reducer: persistedReducer,
  middleware: (getDefaultMiddleware) => [
    ...getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
      },
      immutableCheck: false,
    }),
    defaultApi.middleware,
  ],
});

export default store;



type TypedDispatch<T> = ThunkDispatch<T, any, AnyAction>;

export type RootState = ReturnType<typeof store.getState>;
export const useAppDispatch = () => useDispatch<TypedDispatch<RootState>>();

const persistor = persistStore(store);

export { persistor };

My component:

// Use the query in a component
const MyComponent = () => {
  const {
    data: products,isLoading,isSuccess,isFetching
  } = useProductsQuery();
  
  useEffect(() => {
    console.log("๐Ÿš€ ~ file: index.tsx:22 ~ isLoading:", isLoading)
    console.log("๐Ÿš€ ~ file: index.tsx:22 ~ isSuccess:", isSuccess)
    console.log("๐Ÿš€ ~ file: index.tsx:22 ~ isFetching:", isFetching)
  },[isLoading,isSuccess,isFetching])
  // ...
}

I know the request if being made from watching Network tab but also every time I refresh the page, console return:

๐Ÿš€isLoading: true

๐Ÿš€ isSuccess: false

๐Ÿš€ isFetching: true

๐Ÿš€ isLoading: false

๐Ÿš€ isSuccess: true

๐Ÿš€ isFetching: false

Already tried setting providesTags to [] and cacheTime: 3600000 // cache for 1 hour

I expect to have endpoint called only once I load page for the first time.


Solution

  • The library you are using provides in-memory caching, which means that the cache is alive as long as your page is alive. Cache is cleared and network fetch is initiated every time you refresh the page.

    If you would like to persist network-fetched data across page refresh/reloads, you can try using browser storage options like localstorage, sessionstorage, indexeddb etc.

    Here are some links that might help you: