为何组件挂载及每次加载时useQuery未读取缓存?
React Query useQuery 切换路由后未读取缓存问题解决
问题场景
首次挂载包含useQuery的Login组件时,页面显示加载状态,获取数据后展示内容,已设置cacheTime为300000毫秒(5分钟)。但切换到Home路由后快速返回Login路由时,组件未读取缓存,而是重新请求数据并显示加载状态。
相关代码:
function Login() { const { data, isLoading, isFetching } = useQuery({ queryKey: ["/users"], queryFn: async () => { return fetch("https://jsonplaceholder.typicode.com/users") .then((val) => { return val.json(); }) .then((v) => { return v; }); }, cacheTime : 300000, }); console.log(isLoading, isFetching); if (isLoading) { return <div>Loading ...</div>; } return ( <div> <div style={{ margin: "20px 20px 20px 0px" }}>Login</div> <hr /> {data?.map((eachdata) => { return <div key={eachdata.id}>{eachdata.username}</div>; })} </div> ); } export { Login }; //Home page function Home() { return ( <div> <div style={{ margin: "20px 20px 20px 0px" }}>Home</div> </div> ); }
问题根源
React Query中,cacheTime仅控制缓存数据的保留时长,但默认staleTime为0毫秒——这意味着数据一旦获取完成就会被标记为「过时」。当组件重新挂载时,即使缓存数据仍在cacheTime有效期内,Query会因为数据过时触发新请求;同时如果渲染逻辑仅通过isLoading判断加载状态,可能会忽略缓存数据的存在(isLoading仅在首次无缓存加载时为true,重新挂载有缓存时isLoading为false,isFetching为true)。此外,若未在App顶层正确配置QueryClientProvider,会导致缓存无法跨组件共享。
解决方案
1. 设置staleTime,让数据保持新鲜
给useQuery添加staleTime配置,值与cacheTime一致(5分钟),这样在数据过期前,组件重新挂载会直接读取缓存,不会发起新请求:
const { data, isLoading, isFetching } = useQuery({ queryKey: ["/users"], queryFn: async () => { const res = await fetch("https://jsonplaceholder.typicode.com/users"); return res.json(); }, cacheTime: 300000, staleTime: 300000, // 添加此行 });
2. 区分isLoading与isFetching,优化渲染逻辑
isLoading对应首次无缓存加载,isFetching对应后台刷新请求。修改渲染逻辑,确保有缓存数据时优先展示,仅在首次加载时显示Loading:
if (isLoading) { return <div>Loading ...</div>; } return ( <div> <div style={{ margin: "20px 20px 20px 0px" }}>Login</div> <hr /> {/* 可选:后台刷新时显示提示,不替换现有内容 */} {isFetching && <div style={{ color: '#666' }}>正在刷新数据...</div>} {data?.map((eachdata) => { return <div key={eachdata.id}>{eachdata.username}</div>; })} </div> );
3. 确保QueryClient全局共享
在App顶层配置QueryClientProvider,保证所有路由组件使用同一个QueryClient实例,缓存才能跨路由共享:
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { Routes, Route } from 'react-router-dom'; import { Login } from './Login'; import { Home } from './Home'; const queryClient = new QueryClient(); function App() { return ( <QueryClientProvider client={queryClient}> <Routes> <Route path="/login" element={<Login />} /> <Route path="/" element={<Home />} /> </Routes> </QueryClientProvider> ); } export default App;
内容的提问来源于stack exchange,提问作者hossein olfat
相关产品推荐
相关产品推荐

