React JS中为何无法删除数组的第一个元素?
问题描述
我有一系列复选框,勾选复选框时会将对应复选框的id添加到数组中,取消勾选时则会将对应id从数组中移除,其余逻辑均运行正常,但存在一个异常现象:我第一个点击的复选框(会成为数组的首项)永远无法被移除,也就是数组的第一个元素始终无法删除。
以下是复选框发生状态变更时触发的处理函数代码:
const [genres, setGenres] = useState([]) const checkChange = event => { const targetId = event.target.id const indexOfTargetId = genres.indexOf(targetId) if (indexOfTargetId === -1) setGenres([...genres, targetId]) else genres.splice(indexOfTargetId, indexOfTargetId) }
问题原因
代码存在两个核心错误:
Array.splice()方法的第二个参数是需要删除的元素个数,不是删除操作的截止索引。当前代码传入的是目标id对应的索引值:当要删除的是数组首项时,索引值为0,相当于传入删除数量0,不会删除任何元素;当目标元素索引大于0时,传入的索引值为1、2这类正整数,碰巧符合删除1个元素的要求,才会表现为其余逻辑正常。- else分支直接调用
splice修改原state数组,既没有调用setGenres触发视图更新,还违反了React state不可变的原则,本身就是不规范的写法。
修复方案
方案1:修正原有splice逻辑
先浅拷贝原数组避免直接修改state,同时修正splice的参数,最后通过setGenres更新状态:
const [genres, setGenres] = useState([]) const checkChange = event => { const targetId = event.target.id const indexOfTargetId = genres.indexOf(targetId) if (indexOfTargetId === -1) { setGenres([...genres, targetId]) } else { const newGenres = [...genres] // 第二个参数固定传1,代表仅删除当前索引位置的1个元素 newGenres.splice(indexOfTargetId, 1) setGenres(newGenres) } }
方案2:更简洁稳妥的写法
用filter方法直接生成过滤后的新数组,同时配合setState的函数式更新,避免闭包拿到旧state值的隐患:
const [genres, setGenres] = useState([]) const checkChange = event => { const targetId = event.target.id setGenres(prevGenres => prevGenres.includes(targetId) ? prevGenres.filter(id => id !== targetId) : [...prevGenres, targetId] ) }
内容的提问来源于stack exchange,提问作者Jon Stephen
相关产品推荐
相关产品推荐

