React Redux Toolkit Query 数据缓存未生效问题求助
问题:RTK Query 数据未持久化缓存,页面刷新重复请求
在React应用中使用@reduxjs/toolkit/query的useQuery钩子从API获取数据,每次刷新页面都会重新发起请求,即使设置了cacheTime: 3600000也无法实现仅首次加载调用接口的需求。通过网络面板确认请求每次刷新都会发送,控制台输出状态变化如下:
🚀 ~ file: index.tsx:22 ~ isLoading: true 🚀 ~ file: index.tsx:22 ~ isSuccess: false 🚀 ~ file: index.tsx:22 ~ isFetching: true 🚀 ~ file: index.tsx:22 ~ isLoading: false 🚀 ~ file: index.tsx:22 ~ isSuccess: true 🚀 ~ file: index.tsx:22 ~ isFetching: false
代码片段:API定义
// 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'], // 位置错误 } } }) }), })
代码片段: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", // 未包含RTK Query的reducer ], }; 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 };
代码片段:组件使用
// 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]) // ... }
问题原因
- providesTags位置错误:
providesTags是endpoint的配置项,应该直接放在builder.query的参数中,而非嵌套在query函数返回的对象里,之前的写法不会生效。 - RTK Query缓存未持久化:RTK Query的缓存数据存在其对应的Redux reducer(
defaultApi)中,但当前redux-persist的whitelist只包含了auth,未将defaultApi加入持久化列表,页面刷新后Store中的缓存数据被清空,导致必须重新请求。
解决方案
1. 修正providesTags的位置
修改API定义,将providesTags移到builder.query的配置对象中:
products: builder.query<Product[], void>({ query: () => ({ url: `/api/user/products`, }), providesTags: ['products'], // 调整到正确位置 })
2. 将RTK Query的reducer加入持久化白名单
修改persistConfig的whitelist,添加RTK Query的reducerPath(即defaultApi):
const persistConfig = { key: "primary", version: 15, storage, migrate: createMigrate(migrations, { debug: false }), whitelist: [ "auth", "defaultApi", // 加入RTK Query的reducer ], };
3. 调整缓存时长(可选)
如果需要延长缓存数据的保留时间,可以设置keepUnusedDataFor(默认60秒)和cacheTime(默认5分钟):
products: builder.query<Product[], void>({ query: () => ({ url: `/api/user/products`, }), providesTags: ['products'], keepUnusedDataFor: 3600, // 数据未被使用时保留1小时 cacheTime: 3600000, // 缓存整体保留1小时 })
完成以上修改后,页面刷新时会从redux-persist持久化的存储中读取之前的缓存数据,无需重新发起请求。
内容的提问来源于stack exchange,提问作者Ianagos
相关产品推荐
相关产品推荐

