React中Promise.all().then()先于单个Promise的setState渲染触发的问题
问题分析
核心问题是你当前的Promise.all只等待了fetch请求完成,但每个请求的后续处理(比如setTimeout模拟的耗时逻辑)并没有被纳入Promise.all的等待队列。所以当所有fetch请求返回后,Promise.all.then就会立刻执行,设置done状态,但此时单个请求的then里的setState可能还在排队执行,导致进度条提前隐藏,数据还没完全更新。
解决方案
把每个请求的完整处理流程(包括fetch、后续逻辑、setState)都封装成一个独立的Promise,让Promise.all等待所有完整流程结束后再执行状态更新。
修正后的代码示例
import { useState, useEffect } from 'react'; function ResourceTable() { const [data, setData] = useState({}); const [done, setDone] = useState(false); const totalRequests = 20; useEffect(() => { // 封装每个请求的完整流程为Promise const requestPromises = Array.from({ length: totalRequests }, (_, index) => { return new Promise((resolve) => { // 模拟fetch请求 fetch(`https://api.example.com/resource/${index}`) .then(res => res.json()) .then(rawData => { // 模拟耗时处理逻辑 setTimeout(() => { const processedData = { [index]: rawData }; // 更新数据 setData(prev => ({ ...prev, ...processedData })); console.log(`Render ${Object.keys(data).length + 1}`); resolve(); // 只有当整个流程完成后才resolve }, Math.random() * 1000); }); }); }); // 等待所有完整流程结束 Promise.all(requestPromises).then(() => { console.log(`Promise.all.then: ${Object.keys(data).length}`); setDone(true); }); }, []); return ( <div> {/* 进度条 */} <div style={{ width: '100%', height: '20px', backgroundColor: '#eee', marginBottom: '20px' }}> <div style={{ width: `${(Object.keys(data).length / totalRequests) * 100}%`, height: '100%', backgroundColor: done ? 'red' : 'green' }} /> </div> {/* 资源表格 */} <table border="1"> <thead> <tr> <th>ID</th> <th>内容</th> </tr> </thead> <tbody> {Object.entries(data).map(([id, content]) => ( <tr key={id}> <td>{id}</td> <td>{content}</td> </tr> ))} </tbody> </table> </div> ); } export default ResourceTable;
关键改动说明
- 每个请求不再直接返回
fetch的Promise,而是用新Promise包裹整个流程,只有当耗时处理和setState逻辑完成后,才调用resolve()。 Promise.all现在等待所有完整请求流程的Promise,确保所有数据更新完成后,再设置done状态隐藏进度条。- 这样就能保证
Promise.all.then的打印顺序在最后一个Render之后,进度条会在所有数据都渲染完成后才变为红色。
额外优化建议
如果担心频繁调用setState导致性能问题,可以考虑:
- 批量更新数据:把所有处理后的结果缓存起来,最后一次性
setState,但会失去实时进度的显示效果。 - 使用
useReducer替代useState,更高效地处理复杂状态更新逻辑。
内容的提问来源于stack exchange,提问作者0stone0
相关产品推荐
相关产品推荐

