使用useQuery实现数据筛选时onChange触发refetch更新异常问题
问题原因
React的状态更新是异步批量执行的,调用setFilterGenre/setFilterText后,当前执行上下文内的filterGenre/filterText仍然是更新前的旧值,此时立刻调用query.refetch(),请求携带的就是上一次的筛选参数,和你遇到的现象完全吻合:
- 第一次点击comedy时,refetch用的还是初始空值,和之前的查询参数一致,react-query默认复用缓存不会发起新请求,后续状态才更新为comedy
- 第二次点击Drama时,refetch用的是已经更新完成的comedy值,所以请求参数为
?genres=comedy,后续状态才更新为Drama
同时你当前的用法不符合react-query的设计规范,额外用useState存储接口返回的shows数据,还存在状态不同步的隐患。
解决方案
按照react-query的设计逻辑修改代码,将筛选参数加入查询key,参数变化时react-query会自动发起新请求,无需手动调用refetch:
1. 修改查询逻辑
const [genres, setGenres] = useState([]); const [filterGenre, setFilterGenre] = useState(""); const [filterText, setFilterText] = useState(""); // 将筛选参数加入query key数组,参数变化自动触发重新查询 const query = useQuery(["show-page", filterGenre, filterText], () => api.search(filterGenre, filterText)); const queryGenre = useQuery("genres", api.genres, { onSuccess: (data) => setGenres(Object.keys(data.data.genres)), }); // 仅需更新筛选状态,无需手动调用refetch const handleSelect = (e) => { setFilterGenre(e.target.value); }; const handleInput = (e) => { setFilterText(e.target.value); };
2. 修改渲染逻辑
移除多余的shows状态,直接使用react-query返回的查询数据,同时将下拉框和输入框改为受控组件,避免状态和显示不一致:
<> {query.isLoading && <Spinner />} {query.isSuccess && ( <> <select name="genre" onChange={handleSelect} value={filterGenre}> <option value="">All</option> {genres.map((genre) => { return <option key={genre} value={genre}>{genre}</option>; })} </select> <input type="text" onChange={handleInput} value={filterText} /> <div className="container-show-page"> {query.data.data.shows.map((show) => { return ( <div key={show.id} className="card-show-page"> <img src={show.poster} alt={show.name} className="image-show-page" /> </div> ); })} </div> </> )} </>
内容的提问来源于stack exchange,提问作者jeyremd
相关产品推荐
相关产品推荐

