如何确保React set钩子按顺序同步执行,连续调用状态更新不丢失?
问题原因
你遇到的问题是React状态更新的批量更新特性导致的:你当前的updateLicenseInfo函数每次调用时,读取的都是当前闭包中缓存的licenseInfo旧值,连续两次调用时,第二次读取的还是第一次修改前的状态,因此第二次更新会直接覆盖第一次的修改,最终只有最后一次更新生效。
解决方案
方案1:修改更新函数为函数式更新(最推荐)
React的setState支持传入函数作为参数,函数会接收上一次更新完成后的最新状态作为入参,完全避免闭包旧值的问题,无需修改业务调用代码:
const updateLicenseInfo = (index, licenseInfoKey, licenseInfoVal) => { // 改用函数式更新,基于最新的prev状态修改 setLicenseInfo(prevLicenseInfo => { const licenseInfoItems = [...prevLicenseInfo]; const foundLicenseInfo = { ...licenseInfoItems[index] }; foundLicenseInfo[licenseInfoKey] = licenseInfoVal; licenseInfoItems[index] = foundLicenseInfo; return licenseInfoItems; }); };
修改后你原来的连续调用逻辑可以直接保留,两次更新会自动基于上一次的结果串行执行,不会互相覆盖。
方案2:封装Promise实现显式串行等待
如果你的后续更新逻辑强依赖前一次更新完成后的状态值,可以将更新函数封装为返回Promise的形式,用await显式等待前一次更新完成:
const updateLicenseInfo = (index, licenseInfoKey, licenseInfoVal) => { return new Promise(resolve => { setLicenseInfo(prevLicenseInfo => { const licenseInfoItems = [...prevLicenseInfo]; const foundLicenseInfo = { ...licenseInfoItems[index] }; foundLicenseInfo[licenseInfoKey] = licenseInfoVal; licenseInfoItems[index] = foundLicenseInfo; // 更新完成后resolve resolve(licenseInfoItems); return licenseInfoItems; }); }) }; // 调用时串行等待 postData('/api/licenseInfo/createLicenseInfoAndCreateRelationship', { LicenseNumber, RequestLineItemID: procurementLine.ID }) .then((res) => res.json()) .then(async (r) => { await updateLicenseInfo(licenseIndex, 'ID', r.ID); await updateLicenseInfo(licenseIndex, 'added', true); })
方案3:合并为单次更新(当前场景最优)
你当前的场景两次修改的是同一个下标对应的对象属性,可以直接合并为一次状态更新,减少重渲染次数:
postData('/api/licenseInfo/createLicenseInfoAndCreateRelationship', { LicenseNumber, RequestLineItemID: procurementLine.ID }) .then((res) => res.json()) .then((r) => { setLicenseInfo(prev => { const newLicenseInfo = [...prev]; newLicenseInfo[licenseIndex] = { ...newLicenseInfo[licenseIndex], ID: r.ID, added: true }; return newLicenseInfo; }); })
内容的提问来源于stack exchange,提问作者klaurtar1
相关产品推荐
相关产品推荐

