如何使用useState配合React Query(useQuery)实现动态接口参数更新获取数据
问题根因
- useQuery的查询键是触发重新请求的核心依据,你当前使用固定字符串
'productDetail'作为查询键,即使gender、age等参数更新,查询键未变化,react-query会直接复用之前的缓存结果,不会发起新请求。 - 原有代码存在两处语法错误:
- 请求地址拼接时误用未定义变量
female,应该用state存储的gender变量 - onChange事件中取字段名时写死
e.target.age,应该读取输入框的name属性匹配对应字段
- 请求地址拼接时误用未定义变量
- fetch配置中
withCredentials是axios的参数,原生fetch对应配置为credentials: 'include',也会导致请求携带凭证异常。
修复实现
你只需要将所有影响请求结果的参数(id、gender、age)都放到查询键数组中,react-query会自动监听这些参数的变化,参数更新时自动触发重新请求,同时修正语法错误即可,完整代码如下:
import { useState } from 'react'; import { useQuery } from 'react-query'; // 假设id、token是你页面已经获取到的变量 const ProductDetailPage = ({ id, token }) => { // 存储用户输入的参数 const [inputs, setInputs] = useState({ age: '30', gender: 'female', }); const { age, gender } = inputs; // 修正onChange逻辑,通过输入框name属性匹配对应字段 const onChange = (e) => { setInputs({ ...inputs, [e.target.name]: e.target.value }); }; // 请求函数 const fetchDetail = async () => { const res = await fetch(`https://api.minsu.com/product/${id}?gender=${gender}&age=${age}`, { headers: { Authorization: `Bearer ${token}`, }, credentials: 'include' }); if (!res.ok) throw new Error('请求失败'); return res.json(); }; // 重点:把所有请求依赖参数放到查询键数组中 const { data: ProductDetail, status, error, isFetching } = useQuery( ['productDetail', id, gender, age], fetchDetail, { notifyOnChangeProps: ['data'], staleTime: 100000000, } ); // 状态兜底处理 if (status === 'loading') return <div>加载中...</div>; if (status === 'error') return <div>请求错误:{error.message}</div>; return ( <div> <div> <input type="number" name="age" value={age} onChange={onChange} placeholder="请输入年龄" /> <select name="gender" value={gender} onChange={onChange} > <option value="male">男</option> <option value="female">女</option> </select> </div> {isFetching && <div>数据更新中...</div>} {/* 渲染详情数据 */} <div className="detail-content"> <h1>{ProductDetail.title}</h1> <p>{ProductDetail.desc}</p> {/* 其他详情字段自行补充 */} </div> </div> ); }; export default ProductDetailPage;
可选优化
如果不需要用户每输入一个字符就立刻发请求,可以添加防抖逻辑,等用户停止输入300ms后再发起请求,避免频繁调用接口:
import { useState, useEffect } from 'react'; // ...其他引入保持不变 const ProductDetailPage = ({ id, token }) => { const [inputs, setInputs] = useState({ age: '30', gender: 'female' }); // 新增防抖后的参数state const [debouncedInputs, setDebouncedInputs] = useState(inputs); const onChange = (e) => { setInputs({ ...inputs, [e.target.name]: e.target.value }); }; // 防抖逻辑 useEffect(() => { const timer = setTimeout(() => { setDebouncedInputs(inputs); }, 300); return () => clearTimeout(timer); }, [inputs]); const fetchDetail = async () => { // 用防抖后的参数拼接地址 const { age, gender } = debouncedInputs; const res = await fetch(`https://api.minsu.com/product/${id}?gender=${gender}&age=${age}`, { // 其他配置保持不变 }); // ...其他请求逻辑保持不变 }; // 查询键替换为防抖后的参数 const { data: ProductDetail, status, error, isFetching } = useQuery( ['productDetail', id, debouncedInputs.gender, debouncedInputs.age], fetchDetail, { staleTime: 100000000, } ); // ...其他渲染逻辑保持不变 }
内容的提问来源于stack exchange,提问作者ssksksks
相关产品推荐
相关产品推荐

