如何为同一RTK Query端点的不同查询参数设置动态缓存有效期?
同一RTK Query端点按请求参数配置不同缓存有效期的方案
RTK Query本身不支持直接为同一端点的不同查询参数设置差异化的keepUnusedDataFor,但可以通过以下几种方案实现类似需求:
方案1:拆分端点(最简洁)
如果不同参数对应的数据集缓存需求差异明确,可以直接将原端点拆分为多个独立端点,每个端点单独配置keepUnusedDataFor。
示例代码:
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; export const dataApi = createApi({ reducerPath: 'dataApi', baseQuery: fetchBaseQuery({ baseUrl: '/api' }), endpoints: (builder) => ({ // 短缓存数据集端点 getShortLivedDataset: builder.query({ query: (params) => `/data?type=${params.type}`, keepUnusedDataFor: 60, // 缓存1分钟 }), // 长缓存数据集端点 getLongLivedDataset: builder.query({ query: (params) => `/data?type=${params.type}`, keepUnusedDataFor: 3600, // 缓存1小时 }), }), }); export const { useGetShortLivedDatasetQuery, useGetLongLivedDatasetQuery } = dataApi;
方案2:手动修改缓存条目过期时间
利用RTK Query的transformResponse钩子,结合updateQueryData工具,在请求完成后根据参数动态修改对应缓存条目的过期时间。
示例代码:
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; export const dataApi = createApi({ reducerPath: 'dataApi', baseQuery: fetchBaseQuery({ baseUrl: '/api' }), endpoints: (builder) => ({ getDataset: builder.query({ query: (params) => `/data?type=${params.type}`, keepUnusedDataFor: 0, // 先设为0,后续手动覆盖 transformResponse: (response, meta, arg) => { // 根据参数判断缓存时长(示例:temp类型缓存1分钟,其他缓存1小时) const cacheDuration = arg.type === 'temp' ? 60 : 3600; const expiresTime = Date.now() + cacheDuration * 1000; // 更新当前缓存条目的过期时间 meta.dispatch(dataApi.util.updateQueryData('getDataset', arg, (draft) => { draft.expiresTime = expiresTime; })); return response; }, }), }), }); export const { useGetDatasetQuery } = dataApi;
方案3:自定义缓存逻辑(最高自由度)
通过skipCache: true关闭RTK Query的默认缓存,自行在Redux Slice或组件中实现缓存管理,包括数据存储、过期时间设置和自动清理逻辑。
示例代码:
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; import { createSlice } from '@reduxjs/toolkit'; import { useSelector, useDispatch } from 'react-redux'; import { useEffect } from 'react'; // 自定义缓存Slice const cacheSlice = createSlice({ name: 'dataCache', initialState: {}, reducers: { setCache: (state, action) => { const { key, data, expiresIn } = action.payload; state[key] = { data, expiresAt: Date.now() + expiresIn * 1000, }; }, clearExpiredCache: (state) => { const now = Date.now(); Object.keys(state).forEach(key => { if (state[key].expiresAt < now) delete state[key]; }); }, }, }); export const { setCache, clearExpiredCache } = cacheSlice.actions; export const dataCacheReducer = cacheSlice.reducer; // 定义API,跳过RTK Query默认缓存 export const dataApi = createApi({ reducerPath: 'dataApi', baseQuery: fetchBaseQuery({ baseUrl: '/api' }), endpoints: (builder) => ({ getDataset: builder.query({ query: (params) => `/data?type=${params.type}`, skipCache: true, }), }), }); // 组件中使用自定义缓存 function DataComponent({ type }) { const cacheKey = `dataset_${type}`; const cachedData = useSelector(state => state.dataCache[cacheKey]); const { data, error, isLoading } = dataApi.useGetDatasetQuery({ type }); const dispatch = useDispatch(); useEffect(() => { if (data) { const expiresIn = type === 'temp' ? 60 : 3600; dispatch(setCache({ key: cacheKey, data, expiresIn })); } // 每分钟清理一次过期缓存 const interval = setInterval(() => dispatch(clearExpiredCache()), 60000); return () => clearInterval(interval); }, [data, type, dispatch]); // 优先使用未过期的缓存数据 const displayData = cachedData?.expiresAt > Date.now() ? cachedData.data : data; if (isLoading) return <div>加载中...</div>; if (error) return <div>加载失败</div>; return <div>{JSON.stringify(displayData)}</div>; }
方案选择建议
- 若参数对应的缓存规则分组清晰,优先选择拆分端点,实现成本最低且易维护;
- 若不想拆分端点,可使用手动修改过期时间的方案,在原有端点基础上扩展;
- 若需要完全自定义缓存策略(如LRU淘汰、多维度过期规则),则选择自定义缓存逻辑。
内容的提问来源于stack exchange,提问作者Indranil Mondal
相关产品推荐
相关产品推荐

