React Query调用queryClient.setQueryData后缓存无法持久化问题
问题:React Query缓存无法持久化及defaultOptions不生效
调用queryClient.setQueryData后缓存无法持久化,配置的defaultOptions未生效。通过React Query开发者工具可见API调用后数据已存储,但发现gcTimeout属性值为23,尝试各类网上方案后仍未解决。目前能通过getQueryData获取到allMappingAreas数据,但约5分钟后会消失。
相关代码配置
1. app.tsx中的QueryClient配置
const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: Infinity, cacheTime: 100000, // 10分钟 }, }, }); <QueryClientProvider client={queryClient}>
2. 自定义mutation钩子useFetch(hooks/useFetch.ts)
const useFetch = (requests: Request[]) => { const queryClient = useQueryClient(); const fetchDataAndMutate = () => { return requests.map((request) => { const { key, api, save = true, } = request; const {mutate, isLoading} = useMutation({ mutationFn: async (payload) => postUtil(api, payload), onMutate: (variables) => { return {id: 1}; }, onError: (error, variables, context) => { console.log(`Error: ${error}`); }, onSuccess: (response, variables, context) => { if (response.status) { if (response.status === 200) { if (save) queryClient.setQueryData([key], response.data.data); } } else if (response.response.status) { console.log( "response.response.status", response.response.data.Message ); } }, }); return { mutate, isLoading, }; }); }; const mutates = fetchDataAndMutate(); useEffect(() => { requests.forEach((request, index) => { if (request?.init && typeof mutates[index].mutate === "function") mutates[index].mutate(); }); }, []); return mutates; };
3. 钩子使用方式(containers/analysis)
const apiConfig = [ { key: ALL_MAPPING_AREAS, api: getAllMappingAreasApi, init: true, }, { key: MAPPING_AREA_DETAIL, api: getMappingAreaDetailApi, }, ]; const mutates = useFetch(apiConfig); const [ getAllMappingAreas, getBoundedAreaDetail, ] = mutates; const allMappingAreas = queryClient.getQueryData([ALL_MAPPING_AREAS]); const mappingAreaDetail = queryClient.getQueryData([MAPPING_AREA_DETAIL]);
问题根源与解决方案
问题根源
- defaultOptions未生效:
defaultOptions仅对useQuery创建的查询生效,你用useMutation配合setQueryData手动设置的缓存,不受queries配置项的约束。 - 缓存5分钟后消失:React Query的垃圾回收机制会清理无订阅的缓存项,默认等待时间为5分钟(对应
gcTimeout)。你仅通过setQueryData添加缓存,但没有组件用useQuery订阅该查询键,所以缓存会被自动回收。
解决步骤
方案1:用useQuery替代mutation初始化数据
对于需要持久化缓存的初始化请求,改用useQuery,这样defaultOptions的配置会生效,且订阅会阻止垃圾回收:
const useFetchQueries = (requests: Request[]) => { return requests.map((request) => { const { key, api, init = false } = request; const query = useQuery({ queryKey: [key], queryFn: () => postUtil(api), // 适配POST请求的查询函数 enabled: init, // 控制是否自动执行请求 staleTime: Infinity, cacheTime: 100000, }); return { refetch: query.refetch, isLoading: query.isLoading, data: query.data, }; }); };
方案2:手动添加查询订阅(保留mutation场景)
如果必须用mutation设置缓存,需在组件中添加空订阅,阻止垃圾回收:
// 在需要缓存的组件中添加 useQuery({ queryKey: [ALL_MAPPING_AREAS], queryFn: () => Promise.resolve(null), enabled: false, // 不自动执行请求 cacheTime: 100000, staleTime: Infinity, });
方案3:手动更新缓存项配置
通过setQueryData设置缓存后,手动修改缓存项的垃圾回收策略:
queryClient.setQueryData([key], response.data.data); // 覆盖缓存项的cacheTime配置 queryClient.getQueryCache().get([key])?.setOptions({ cacheTime: 100000 });
内容的提问来源于stack exchange,提问作者sana arshed
相关产品推荐
相关产品推荐

