本地环境useQuery仅首次加载数据不重复请求,生产环境正常
React中useQuery仅首次加载获取数据的问题解决
问题原因分析
- useQuery默认缓存机制:useQuery核心特性是缓存查询结果,只要查询键
["todaysAbsent", branchId]不变,后续组件渲染会直接复用缓存数据,不会重新发起请求。 - 冗余的useState同步:你通过
onSuccess将useQuery的data同步到本地useState,不仅完全没必要,还会导致数据更新不及时——当useQuery重新获取数据时,本地state不会自动同步。 - 错误的数组遍历用法:原代码用
filter遍历数据,但filter的作用是过滤元素(需返回布尔值),而非遍历执行副作用,这属于API误用。
解决方案
1. 移除冗余useState,用useMemo处理数据转换
useQuery本身会管理数据状态,直接基于返回的allAttendance用useMemo处理数据,避免重复计算:
const { data: allAttendance, isLoading: attendanceIsLoading, isError: attendanceIsError, } = useQuery( ["todaysAbsent", branchId], async () => myAxios(`/all_attendance/${moment().format("MM")}/${moment().format("YYYY")}/?branch_id=${branchId ?? ""}`) ); // 用useMemo处理数据转换,仅在allAttendance变化时重新计算 const todayAttendance = React.useMemo(() => { if (!allAttendance?.data) return []; return Object.values(allAttendance.data).map(({ attendance, name, position, information_user }, i) => ({ attendance: attendance[moment().format("YYYY-MM-DD")], id: i, status: attendance[moment().format("YYYY-MM-DD")]?.status, // 加可选链避免报错 name, position, information_user })); }, [allAttendance]);
2. 配置useQuery的重新获取策略
根据业务需求选择以下方式触发重复获取:
- 窗口聚焦时自动刷新:适合用户切回页面需要更新数据的场景
const { ... } = useQuery( ["todaysAbsent", branchId], async () => {/* 请求逻辑 */}, { refetchOnWindowFocus: true } // 默认开启,若之前设为false可重新打开 ); - 设置数据过期时间:指定数据多久后变为"过期",自动重新请求
const { ... } = useQuery( ["todaysAbsent", branchId], async () => {/* 请求逻辑 */}, { staleTime: 60000 } // 1分钟后数据过期,下次渲染自动请求 ); - 手动触发刷新:通过
refetch方法在特定时机(如按钮点击)主动发起请求const { data: allAttendance, isLoading: attendanceIsLoading, isError: attendanceIsError, refetch // 获取手动刷新方法 } = useQuery( ["todaysAbsent", branchId], async () => {/* 请求逻辑 */} ); // 示例:点击按钮刷新 const handleRefresh = () => refetch();
3. 确保查询键能正确触发更新
查询键["todaysAbsent", branchId]中,branchId必须是基本类型(字符串/数字)。如果branchId是引用类型(如对象),要提取其中的唯一标识作为查询键的一部分,否则useQuery会认为查询键未变化,不会重新请求。
内容的提问来源于stack exchange,提问作者Naser
相关产品推荐
相关产品推荐

