React同一事件回调内调用setState后useState状态未更新问题
问题原因
React函数组件里useState触发的状态更新是异步批处理的,同一段同步执行的事件回调中,调用状态更新方法后,当前函数闭包里捕获的状态常量不会同步变更,必须等当前同步逻辑全部执行完成、组件完成重渲染后,新的状态值才会在下次渲染生成的函数作用域中生效。
你在同一个onClick回调里调用setUsers后立刻遍历users,拿到的永远是当前渲染周期绑定的旧状态值,这是Hooks的闭包特性导致的正常表现,不是框架bug。
修复方案
你不需要等状态更新完成再做统计,filter生成的afterFilter本身就是删除操作完成后的最新航班数据,直接基于这个值做统计即可,完全不需要等待状态生效。
修正后的代码如下:
const [users, setUsers] = useState([]); // 调整deleteFlight,返回过滤后的最新数组 const deleteFlight = (num) => { const afterFilter = users.filter((user) => user.numFlight !== num); setUsers(afterFilter); return afterFilter; }; <button onClick={() => { const inp = numFlightInp.current.value; const targetFlightNum = Number(inp); // 先做存在性校验,避免无意义的状态更新 if (!checkDuplicateFlight(targetFlightNum)) { alert("not found match"); return; } // 执行删除,拿到最新的航班列表 const latestUserList = deleteFlight(targetFlightNum); alert("deleted"); // 直接基于最新列表统计数据 let passengerCnt = 0; let totalFlightCnt = 0; latestUserList.forEach((user) => { passengerCnt += user.passenger; totalFlightCnt++; }); setFlightCnt2(totalFlightCnt); setPassengerCnt2(passengerCnt); }} > delete </button>
额外说明
- 你原有代码的执行顺序有问题:先执行删除操作再做航班存在性校验,会导致输入不存在的航班号时,也会触发一次无意义的
setUsers调用和组件重渲染,把校验逻辑前置性能更好。 - 这类场景不需要用
useEffect监听users变化再做统计,会多绕一层渲染逻辑,属于不必要的复杂度。 - 不要用Ref强行存储最新状态来绕开闭包,属于过度设计,你在调用
setUsers之前就已经拿到了最新的数据集,直接复用即可。
内容的提问来源于stack exchange,提问作者Lior98
相关产品推荐
相关产品推荐

