React异步回调更新useState数组状态如何按service_months保留元素顺序
解决异步请求回调更新数组顺序错乱问题
你现在遇到的问题本质是异步请求返回顺序不固定,直接追加会打乱原遍历顺序,有两种常用的稳定解决方案:
方案1:按索引占位更新(支持边加载边渲染)
每个请求对应service_months的固定索引,请求返回后直接填充到数组对应位置,和返回顺序无关:
useEffect(() => { // 初始化和service_months长度一致的空数组,确定索引对应关系 setTheArray(new Array(service_months.length).fill(null)) service_months.forEach((service_month, index) => { GET(`/api/report/${props.user_id}`, service_month, resp => { setTheArray(oldArray => { const newArray = [...oldArray] // 把返回数据放到对应索引的位置,不会打乱顺序 newArray[index] = resp.data return newArray }) }) }) }, [service_months])
方案2:等待所有请求完成后一次性更新(适合全量展示场景)
将回调式请求封装为Promise,用Promise.all按原顺序收集所有返回结果后,一次性更新数组:
// 先封装回调风格的GET为Promise形式 const getReport = (userId, serviceMonth) => { return new Promise((resolve) => { GET(`/api/report/${userId}`, serviceMonth, resp => resolve(resp.data)) }) } useEffect(() => { // 按原遍历顺序生成Promise数组 const requestList = service_months.map(month => getReport(props.user_id, month)) // Promise.all返回的结果顺序和输入Promise的顺序完全一致 Promise.all(requestList).then(resultList => { setTheArray(resultList) }) }, [service_months])
补充说明
- 方案1的优势是无需等待所有请求完成,先返回的请求数据可以先渲染到对应位置,用户感知更快
- 方案2如果需要兼容部分请求失败的场景,可以把
Promise.all替换为Promise.allSettled,再过滤出成功的结果即可 - 两种方案都能保证最终
theArray的元素顺序和service_months的遍历顺序完全一致
内容的提问来源于stack exchange,提问作者Unviray
相关产品推荐
相关产品推荐

