React useState中spread operator更新数组为何缺失后续元素
React useState更新指定索引数组项丢失后续元素问题修复
问题原因
你的代码拿不到索引14之后的元素,核心是三类错误:
- 错误使用了可变数组方法
splicesplice会直接修改调用它的原数组,第一次执行wizard.controls.splice(0,14)时,原数组会被直接裁剪,删除前14项,剩下的内容只有原索引14到17共4项。此时再调用wizard.controls.splice(15),当前数组长度仅为4,不存在索引15的位置,自然返回空数组,拿不到后续内容。 - 存在语法和变量拼写错误
修改后的目标对象末尾缺少分隔逗号,且const groups = [...controls.group, ...]中的controls变量未定义,实际应该取提前缓存的subjectControls属性。 - 初始可变写法的隐藏bug:
push方法的返回值是数组更新后的长度,不是修改后的数组本身,你之前给wizard字段赋值的实际是个数字,只是因为直接修改了原状态对象,碰巧看起来功能正常。
正确不可变更新实现
数组不可变操作优先使用slice、扩展运算符这类不会修改原数组的方法,不要用splice、push这类原地修改的方法,正确代码如下:
setFormWizard(wizard => { const subjectControls = wizard.controls[14] // 修正变量名,基于原group属性拼接新内容 const groups = [...subjectControls.group, ...subjectAddressCopy.slice(0, 5)] return { ...wizard, controls: [ // 截取前14项(索引0-13),slice不会修改原数组 ...wizard.controls.slice(0, 14), // 替换索引14的项为修改后的新对象 { ...subjectControls, group: groups, trash: true }, // 截取索引15到数组末尾的所有剩余项 ...wizard.controls.slice(15) ] } })
最佳实践提示
- React状态更新要严格遵守不可变原则,数组操作优先选择返回新数组的非可变方法:新增用扩展运算符、截取用
slice、遍历修改用map、过滤删除用filter。 - 如果一定要用
push、splice这类可变方法,必须先对原状态做一次浅拷贝,在拷贝出来的新数组上操作,避免直接修改原状态导致渲染检测失效。
内容的提问来源于stack exchange,提问作者London804
相关产品推荐
相关产品推荐

