如何让useState的set方法等待状态更新完成后再执行后续逻辑
问题根因
你遇到的两个问题本质是同一个原因导致的:
- React中useState的更新是异步批量执行的,调用
setPage后不会立刻修改当前渲染周期的page变量,紧接着调用updateNews获取到的还是旧的页码值 - 因为每次请求都用了页码1,返回的第一页数据重复拼接进
articles数组,导致渲染时出现重复的element.url作为key,触发重复key警告
解决方案
方案1:通过useEffect监听page变化触发请求(更符合React声明式写法)
直接把updateNews的触发和page状态绑定,page更新后自动执行请求,不需要手动等待setState完成。
修改代码:
- 调整useEffect依赖为
page,page变化自动调用updateNews
// 替换原来的空依赖useEffect useEffect(() => { updateNews(); }, [page])
- 简化fetchMoreData,只需要更新page即可
const fetchMoreData = () => { // 使用函数式更新page,避免闭包导致的页码计算错误 setPage(prevPage => prevPage + 1); };
- 修正updateNews内部的状态更新逻辑,避免闭包问题
const updateNews = async ()=>{ props.setProgress(10); const url = `https://newsapi.org/v2/top-headlines?country=${props.country}&category=${props.category}&apiKey=${props.apiKey}&page=${page}&pageSize=${props.pageSize}`; props.setProgress(30); let data = await fetch(url); props.setProgress(50); let parsedData = await data.json(); props.setProgress(70); if(parsedData) { // 用函数式更新获取最新的articles数组,避免闭包拿到旧值 setArticles(prevArticles => prevArticles.concat(parsedData.articles)); setLoading(false); // 删除冗余的setPage(page)代码,无实际作用 setTotalResults(parsedData.totalResults); } props.setProgress(100); }
方案2:直接传页码参数给updateNews
不需要等待state更新,直接把计算好的新页码作为参数传给请求函数,效率更高。
修改代码:
- 修改updateNews接收目标页码作为参数
const updateNews = async (targetPage)=>{ props.setProgress(10); // 直接用传入的targetPage请求 const url = `https://newsapi.org/v2/top-headlines?country=${props.country}&category=${props.category}&apiKey=${props.apiKey}&page=${targetPage}&pageSize=${props.pageSize}`; props.setProgress(30); let data = await fetch(url); props.setProgress(50); let parsedData = await data.json(); props.setProgress(70); if(parsedData) { setArticles(prevArticles => prevArticles.concat(parsedData.articles)); setLoading(false); setTotalResults(parsedData.totalResults); } props.setProgress(100); }
- 修改fetchMoreData,计算新页码后同时传给setPage和updateNews
const fetchMoreData = () => { const newPage = page + 1; setPage(newPage); updateNews(newPage); };
- 初始化调用时传入第一页的页码
useEffect(() => { updateNews(1); // eslint-disable-next-line }, [])
修改完成后,请求的页码会正确递增,不会重复请求第一页数据,重复key的警告也会自动消失。
内容的提问来源于stack exchange,提问作者Himanshu Poddar
相关产品推荐
相关产品推荐

