React首次渲染时Map.prototype.size显示0的问题排查
问题原因
核心是异步代码的执行顺序错误:
- 在
Promise.allSettled的回调里,你用forEach遍历结果并执行带await的异步逻辑,但forEach不会等待异步函数完成,导致setResponse(newResponses)在所有JSON解析操作完成前就执行了。 - 此时
newResponses里只有初始的旧数据,异步获取的新数据还没被添加进去,所以首次渲染时response.size显示为0。 - 后续异步操作完成后,你修改了
newResponses这个Map对象,但没有再次调用setResponse触发状态更新,React不会主动重新渲染。直到其他操作(比如修改useEffect内容)触发重渲染时,才会读取到已经被修改的Map,此时size数值正确。
修复方案
把forEach替换成Promise.all,等待所有异步处理逻辑完成后再更新状态,同时修正状态不可变的问题:
Promise.allSettled(promises).then(async (results) => { const newResponses = new Map(response); // 用Promise.all等待所有异步操作完成 await Promise.all(results.map(async (result) => { const url = new URL(result.value.url).pathname; if (result.status === 'fulfilled' && result.value.ok) { const data = await result.value.json(); // 不要直接修改原状态,创建新Map后再修改 setRequests((prev) => { const updatedRequests = new Map(prev); updatedRequests.delete(url); return updatedRequests; }); newResponses.set(url, data); } else { setHeaderStates((prev) => ({ ...prev, reload: true, isSaving: false, })); setFetchRequestData((prev) => ({ ...prev, isErrorMessageHidden: false, errorMessage: 'Server request failed.', })); } })); // 所有异步操作完成后,再更新response状态 setResponse(newResponses); });
关键细节说明
- Promise.all替代forEach:
results.map返回一组异步Promise,Promise.all会等待所有Promise完成,确保newResponses已经填充了所有异步获取的数据后,再调用setResponse。 - 状态不可变:之前直接修改
setRequests的prev参数(prev.delete(url))违反了React状态不可变原则,容易导致状态更新异常,现在改为创建新的Map对象再修改。
内容的提问来源于stack exchange,提问作者Ozan
相关产品推荐
相关产品推荐

