React数组逆序填充问题:首次渲染顺序错误刷新后正常如何解决
问题原因
- 核心是异步请求的返回顺序不可控:你在
forEach循环中并行发起多个getProducts接口请求,每个请求的响应时间受网络、服务端处理速度影响,哪个请求先返回,就会先执行setRows将对应数据插入数组,最终rows的顺序是接口响应的先后顺序,和你发起请求的顺序无关。 - 刷新后顺序正确是巧合:大概率是刷新时接口命中了浏览器缓存,先发的请求优先从缓存读取返回,刚好匹配了你期望的顺序,属于不稳定的偶然现象。
修复方案
有两种常用修复方案,可根据场景选择:
方案1:并发请求+统一处理(推荐,性能更高)
先收集所有请求,用Promise.all等待全部请求完成后,按发起请求的原始顺序统一更新rows,既保证顺序正确,又不会损失请求并发性能。
修改后代码如下:
// 调整getProducts,直接返回响应数据,不单独更新状态 const getProducts = async (data) => { try { const response = await productServices.getProductsByTakeoffWizardStep(data); return response.data; } catch (error) { console.log(error.response); return []; // 错误兜底,避免Promise.all终止 } }; const getTakeoffIDs = async () => { var i = 1; try { const response = await takeoffServices.getTakeoffSteps(5); const productRequests = []; // 收集所有产品请求 response.data.forEach((element) => { setSteps((steps) => [...steps, element.description]); setStepsID((stepsID) => [...stepsID, element.stepID]); var data = { StepID: element.stepID, TakeoffID: 4 }; productRequests.push(getProducts(data)); // 收集请求 setStepSequence((stepSequence) => [ ...stepSequence, "Step " + i + "", ]); i = i + 1; }); // 等待所有请求完成,结果顺序和请求发起顺序完全一致 const allProducts = await Promise.all(productRequests); setRows(allProducts); // 一次性更新rows } catch (error) { console.log(error.response); } }; useEffect(() => { setSteps([]); setStepsID([]); setRows([]); getTakeoffIDs(); }, []);
方案2:串行请求(简单直接,性能略低)
如果请求量很小,也可以选择串行发起请求,等前一个请求完成后再发起下一个,保证插入顺序和期望一致:
修改后核心逻辑:
const getTakeoffIDs = async () => { var i = 1; try { const response = await takeoffServices.getTakeoffSteps(5); // 把forEach改为for...of,支持await串行执行 for (const element of response.data) { setSteps((steps) => [...steps, element.description]); setStepsID((stepsID) => [...stepsID, element.stepID]); var data = { StepID: element.stepID, TakeoffID: 4 }; await getProducts(data); // 等待当前请求完成再执行后续逻辑 setStepSequence((stepSequence) => [ ...stepSequence, "Step " + i + "", ]); i = i + 1; } } catch (error) { console.log(error.response); } };
内容的提问来源于stack exchange,提问作者Selim Choueiter
相关产品推荐
相关产品推荐

