React调用API先返回空响应后返回数据问题求助
问题原因
- 代码中请求成功后先执行
setIsLoaded(true),再执行setItems(result)。在React 17及更早版本中,异步回调里的多次状态更新会依次触发重渲染:- 第一次执行
setIsLoaded(true)后,isLoaded变为true,触发重渲染,此时items还未更新,仍是初始的空数组,所以console.log打印空值 - 紧接着执行
setItems(result),再次触发重渲染,此时items已更新为接口返回的数据,所以第二次打印正常
- 第一次执行
- 若使用React 18+版本仍出现该问题,大概率是开启了严格模式,开发环境下严格模式会额外执行一次useEffect检测副作用,该问题仅在开发环境出现,不会影响生产环境。
- 额外注意:你调用的接口返回的根数据是对象,实际业务常用的天气列表在
result.dataseries字段中,直接存储整个result对象会和你初始化的数组类型不匹配,后续遍历操作可能报错。
解决方案
- 调整状态更新顺序,先更新items再更新isLoaded
(result) => { // 先更新数据,再更新加载状态 setItems(result); setIsLoaded(true); }
改动后,第一次状态更新修改items时,isLoaded还是false,触发的重渲染仍走Loading分支,不会执行业务逻辑;第二次更新isLoaded为true时,items已经是最新值,业务逻辑拿到的就是正常数据。
2. 合并状态更新,把三个状态合并为一个状态对象,一次性更新
// 初始化合并状态 const [requestState, setRequestState] = useState({ error: null, isLoaded: false, items: [] }); // 请求成功后一次性更新所有状态 (result) => { setRequestState({ isLoaded: true, items: result, error: null }) } // 后续判断逻辑从requestState中取对应字段即可
- React 18+版本可以用startTransition包裹状态更新,强制批量处理多次更新
import { startTransition } from 'react'; // 更新时用startTransition包裹 (result) => { startTransition(() => { setIsLoaded(true); setItems(result); }) }
内容的提问来源于stack exchange,提问作者Dazeh
相关产品推荐
相关产品推荐

