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.
2
Answers
RTK Query, like Redux itself, is an in-memory-cache. It keeps data around while you navigate around in your application (assuming you navigate correctly with your router library).
When you press F5, you kill the whole app and start it again. In that case, all memory has been erased, and data needs fetching again.
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: