点击提交按钮时React Query重复调用API两次的问题求助
问题描述
点击提交按钮后,API被调用两次:一次参数为{},一次携带有效参数。期望仅调用一次有效请求。
组件代码
const [filter, setFilter] = useState(null); const [typeReport, setTypeReport] = useState(""); const { data: reportBusiness, isFetching } = useGetReportBusiness( { ...filter, }, typeReport ); const { page, pageSize, handleChangePage, handleChangePageSize, clientData, clientTotal, } = usePagination(reportBusiness); const handleSubmit = (values) => { const from = moment(values.dateRange[0]).toISOString(); const to = moment(values.dateRange[1]).toISOString(); setTypeReport(values.typeReport); setFilter({ from, to, }); handleChangePage(1); };
查询函数代码
export const useGetReportBusiness = (params, typeReport) => { return useQuery({ queryKey: [QUERY_KEYS.REPORT_BUSINESS, params, typeReport], queryFn: async () => { console.log("11"); let res; if (typeReport === BUSINESS_CSKH_VALUE) { res = await ReportBusinessApi.getReportBusinessCSKH(params); } else { res = await ReportBusinessApi.getReportBusinessBCP(params); } return res.data?.data; }, }); };
版本信息
"react": "^18.2.0", "@tanstack/react-query": "^5.0.0-alpha.71",
原因分析
- 多次状态更新触发重渲染:
handleSubmit中先后调用setTypeReport和setFilter,两次异步状态更新会导致组件两次重渲染,每次重渲染都会触发useGetReportBusiness执行。第一次重渲染时filter未完成更新,参数为{};第二次重渲染时两个状态都已更新,携带有效参数。 - React 18严格模式影响:开发环境下,React 18的严格模式会重复执行副作用逻辑(包括
useQuery内部的请求触发),进一步加剧重复调用问题。
解决方案
方案1:合并状态,减少重渲染次数
将filter和typeReport合并为一个状态对象,一次setState完成所有更新,避免多次重渲染:
const [reportParams, setReportParams] = useState({ filter: null, type: "" }); const { data: reportBusiness, isFetching } = useGetReportBusiness( reportParams.filter || {}, reportParams.type ); const handleSubmit = (values) => { const from = moment(values.dateRange[0]).toISOString(); const to = moment(values.dateRange[1]).toISOString(); setReportParams({ filter: { from, to }, type: values.typeReport }); handleChangePage(1); };
方案2:给useQuery添加enabled条件,仅在参数有效时发起请求
在查询函数中添加enabled选项,确保只有当参数完整有效时才触发API请求:
export const useGetReportBusiness = (params, typeReport) => { // 判断参数是否有效:params存在from/to,且typeReport不为空 const isEnabled = !!params?.from && !!params?.to && !!typeReport; return useQuery({ queryKey: [QUERY_KEYS.REPORT_BUSINESS, params, typeReport], queryFn: async () => { console.log("11"); let res; if (typeReport === BUSINESS_CSKH_VALUE) { res = await ReportBusinessApi.getReportBusinessCSKH(params); } else { res = await ReportBusinessApi.getReportBusinessBCP(params); } return res.data?.data; }, enabled: isEnabled }); };
方案3:临时关闭React 18严格模式(仅开发环境验证)
如果是严格模式导致的重复调用,可暂时移除index.js中的<React.StrictMode>标签,但不建议长期使用——严格模式有助于提前发现代码潜在问题。
内容的提问来源于stack exchange,提问作者Lăng Rover
相关产品推荐
相关产品推荐

