React-query useQuery重复调用问题及按需API调用需求
问题解决:React-Query 初始API请求重复调用的处理
问题原因
fetchPreviousOverallStatus被多次调用,核心是React-Query的默认配置触发了自动重复获取:
refetchOnWindowFocus: true:窗口聚焦时自动重新请求refetchOnReconnect: true:网络恢复后自动重新请求staleTime: 0:数据加载完成后立即标记为"过时",触发自动刷新
这些默认行为会导致初始请求完成后,额外触发重复请求。
解决方案
1. 配置初始查询,禁止自动重复获取
修改useQuery的配置,关闭自动重获取并设置永久新鲜的缓存规则:
const { isLoading, data, isError, error, isFetching, refetch } = useQuery('overallPreviousStatus', fetchPreviousOverallStatus, { onSuccess, onError, enabled: true, refetchOnWindowFocus: false, // 关闭窗口聚焦时的自动重获取 refetchOnReconnect: false, // 关闭网络恢复后的自动重获取 staleTime: Infinity, // 标记数据永久新鲜,不会触发自动重获取 })
2. 优化模态框查询的触发逻辑
无需通过useEffect手动调用refetchQueries,直接用enabled条件控制请求触发,同时在onSuccess中更新状态:
// 移除原有的fetchPreviousData函数和对应useEffect // 替换模态框的useQuery配置 const { isLoading:isLoading1, data:data1, isError:isError1, error:error1, isFetching:isFetching1 } = useQuery('previousOcsTestResults', fetchPreviousOcsTestResults, { onSuccess: (res) => { setApiData(res.data); // 请求成功后直接更新状态 console.log("Perform side effect after success", res.data); }, onError, enabled: isOpen && dataToFetch === "previous", // 仅当模态框打开且需获取previous数据时触发请求 refetchOnWindowFocus: false, })
3. 避免组件不必要重渲染(可选)
如果父组件频繁重渲染,或environmentMapping每次渲染生成新对象,给useSelector添加深比较器,避免无意义的重渲染:
const environmentMapping = useSelector( (state) => state.env.environmentMapping, (prev, next) => JSON.stringify(prev) === JSON.stringify(next) // 深比较避免浅比较导致的重渲染 );
完整修改后的代码片段
import React, {useState, useMemo} from "react" import Card from "../Common/Card" import {useSelector} from "react-redux" import Overlay from "../Common/Overlay" import axios from "axios" import {apiSubDirectory} from "../../Constants" import {useQuery} from "react-query" export default function OverallOrderCommunicationServiceStatus() { const onSuccess = (data) => { console.log("Perform side effect after success", data.data) } const onError = (error) => { console.log('Perform side effect after error', error) } const [isOpen, setIsOpen] = useState(false); const [dataToFetch, setDataToFetch] = useState(""); const [apiData, setApiData] = useState([]); const environmentMapping = useSelector( (state) => state.env.environmentMapping, (prev, next) => JSON.stringify(prev) === JSON.stringify(next) ); const urlOverallPreviousStatus = `https://jsonplaceholder.typicode.com/posts` const fetchPreviousOverallStatus = () => { return axios.get(urlOverallPreviousStatus) } const { isLoading, data, isError, error, isFetching } = useQuery('overallPreviousStatus', fetchPreviousOverallStatus, { onSuccess, onError, enabled: true, refetchOnWindowFocus: false, refetchOnReconnect: false, staleTime: Infinity }) const fetchPreviousOcsTestResults = () => { return axios.get(`https://jsonplaceholder.typicode.com/posts?a=${environmentMapping[0].previous.environment}`) } const { isLoading:isLoading1, data:data1, isError:isError1, error:error1, isFetching:isFetching1 } = useQuery('previousOcsTestResults', fetchPreviousOcsTestResults, { onSuccess: (res) => { setApiData(res.data); console.log("Perform side effect after success", res.data); }, onError, enabled: isOpen && dataToFetch === "previous", refetchOnWindowFocus: false }) const columns = useMemo(() => [ { Header: "Status", accessor: "title", }, ], []) const handlePopupOpen = (dataToFetch) => { setIsOpen(true); setDataToFetch(dataToFetch); }; const handlePopupClose = () => { setIsOpen(false); }; return ( <React.Fragment> <div className="row"> <div className="col-md-12 ml-sm-auto col-lg-12 mt-5"> <div className="row mt-5"> <div className="card-group"> <Card environmentName={environmentMapping[0].previous.environment} releaseno="Environment" onClick={() => handlePopupOpen("previous")} /> {environmentMapping[0].previous.isEnvironmentReady ? ( isOpen && ( <Overlay environment={environmentMapping[0].previous.environment} onClose={handlePopupClose} show={isOpen} columns={columns} apiData={apiData} /> ) ) : ( <React.Fragment /> )} </div> </div> </div> </div> </React.Fragment> ); }
为什么之前的尝试无效
你尝试在组件卸载时禁用查询的方法,仅对组件卸载后的行为生效,但初始请求的重复调用发生在组件挂载后,是React-Query的自动重获取机制导致的,因此无法解决问题。
内容的提问来源于stack exchange,提问作者Ilyas Patel
相关产品推荐
相关产品推荐

