React使用useState重置major、minor状态后赋值失效问题求助
问题根因
useState的更新是异步批量的,你在handleSelectInput里调用setMajor(majorStates)和setMinor([])后,当前函数作用域内的major、minor变量还是闭包捕获的旧值,不会立刻变成重置后的值,后续你操作的依然是旧数据,所以重置逻辑看似没生效。- 你直接修改了
major数组里的原有对象,属于直接变更state的引用类型值,违反React状态不可变的更新原则,会导致状态更新异常、渲染触发异常。 - 你在循环里反复调用
setMajor、setMinor,而且每次更新都用了闭包内的旧状态值,所以minor会出现累加问题,因为每次setMinor([...minor, res.data[i]])里的minor都是请求发起时的旧值,不是上一轮循环更新后的值。
修正方案
你可以先基于初始的majorStates构造新的major数组,先把接口返回的数据处理完,再一次性更新状态,不要直接修改原有state、不要在循环里反复更新状态。
// 初始状态定义保持不变,单独抽离的初始常量不要直接修改 const majorStates = new Array(10).fill(null).map((_, idx) => ({ tank: idx + 1, material: '', required: 0, actual: 0, difference: 0, crit: 0, percent: 0, })) const [major, setMajor] = useState(majorStates) const [minor, setMinor] = useState([]) const handleSelectInput = async (e) => { const { value } = e.target try { const res = await axios.put(`${PATH}/main-start`, { product: value }) // 深拷贝初始值构造新的major数组,避免修改到初始常量和原有state const newMajor = JSON.parse(JSON.stringify(majorStates)) const newMinor = [] // 先遍历处理所有接口返回数据 res.data.forEach(item => { const requiredWt = parseFloat(item.required_wt) if (item.type === 'MAJOR') { // 找到对应tank的索引,修改新数组里的对象 const tankIdx = newMajor.findIndex(tk => tk.tank === item.tank) if (tankIdx > -1) { newMajor[tankIdx].material = item.material newMajor[tankIdx].required = requiredWt } } else { newMinor.push({ ...item, required_wt: requiredWt }) } }) // 所有数据处理完成后一次性更新状态 setMajor(newMajor) setMinor(newMinor) } catch (err) { console.log(err) } }
如果接口返回的major数据的tank编号和数组下标是一一对应的(比如tank:1对应下标0),可以直接用下标定位,不用findIndex,性能更好。
内容的提问来源于stack exchange,提问作者user15368351
相关产品推荐
相关产品推荐

