如何配置React Query仅在prodCode、pageable变化时发起接口请求
React Query 非预期重复请求修复方案
问题根因
无限重复请求是两个逻辑冲突导致的:
- React Query 判断query key是否变化默认做引用全等校验,如果你在组件渲染时直接声明
pageable对象(比如const pageable = {page: 1, size: 10}),哪怕每次属性值完全一致,渲染生成的对象引用地址都不同,会被判定为依赖变更,触发请求。 - 你在
onSuccess回调中更新Recoil全局状态reviewList,状态变更会触发组件重渲染,重渲染又生成新的pageable引用,反过来再次触发请求,形成死循环。
修复步骤
1. 稳定pageable参数引用
用useMemo包裹pageable声明,仅当它内部实际用到的属性变化时,才生成新的对象引用:
// 示例:如果pageable依赖当前页码、页大小两个状态,只有这两个值变时才更新引用 const pageable = useMemo(() => ({ pageNum: current, pageSize: pageSize }), [current, pageSize])
如果pageable是从父组件传入的props,确保父组件传递的pageable本身是稳定引用,不要在父组件渲染时临时构造对象传参。
2. 补全重拉相关配置,关闭非预期自动触发
在useQuery配置项中补充以下参数,关闭非依赖变化导致的自动请求:
{ enabled: !!prodCode, refetchOnWindowFocus: false, // 新增配置 refetchOnMount: false, // 组件挂载时若存在有效缓存则不重拉 refetchOnReconnect: false, // 网络断连重连时不自动重拉 staleTime: 300000, // 缓存5分钟内视为新鲜数据,不会自动触发后台重拉 }
3. 移除onSuccess中手动维护列表状态的逻辑
在onSuccess里手动拼接数据、同步到外部状态的写法不符合React Query的设计范式,也是触发渲染循环的核心诱因。列表数据直接从useQuery的返回值派生即可,不需要额外存入Recoil全局状态:
// 直接从query返回值取数据,不需要额外维护reviewList状态 const { data: reviewRes } = useQuery( ['getReviewList', prodCode, pageable], () => ReviewApi.getReviewList({ prodCode, pageable }), { enabled: !!prodCode, refetchOnWindowFocus: false, refetchOnMount: false, refetchOnReconnect: false, staleTime: 300000, } ) // 派生最终要用到的列表数据 const reviewList = reviewRes?.returnData ?? []
如果你的场景是滚动加载更多的分页列表,建议直接替换为React Query提供的useInfiniteQuery,原生支持分页数据拼接、触发加载更多等能力,不需要手动维护数组合并逻辑。
最终效果
修改完成后,接口仅会在以下场景触发:
prodCode从空值变为有效值(满足enabled触发条件)prodCode的实际值发生变化pageable内部属性变化导致引用更新(也就是分页参数实际改动时)
不会再出现无意义的循环重复请求。
内容的提问来源于stack exchange,提问作者knwlSeeker
相关产品推荐
相关产品推荐

