You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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])
  // ...
}

问题原因

  1. providesTags位置错误:providesTags是endpoint的配置项,应该直接放在builder.query的参数中,而非嵌套在query函数返回的对象里,之前的写法不会生效。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 18:25:03