React中向状态数组添加外部数组元素后,通过索引实现元素的添加与删除问题
你遇到的移除功能异常问题,主要是两个核心原因导致的:
1. splice的使用逻辑错误
Array.splice()会直接修改原数组,并且它的返回值是被删除的元素组成的数组,而非更新后的完整数组。当你在setTag里执行oldArray.splice(index, 1)时,实际上是把状态设置成了被删除的单个元素,而非剩下的数组,这直接导致了状态混乱,出现错误删除的情况。
2. 索引不匹配的逻辑漏洞
Remove按钮使用的index是来自addData数组的循环索引,但你的tag数组包含了initialData(前4个元素)和后续添加的addData元素,两者的索引完全不对应。比如点击Title 5的Remove按钮时,它会尝试删除tag数组中索引为0的Title 1,这显然和你的需求不符。
修复后的完整代码
下面是修正后的代码,我会逐一解释关键改动点:
import React, { Component } from 'react'; import { render } from 'react-dom'; import './style.css'; interface Idata { name: string; values: number[]; } const initialData: Idata[] = [ { name: 'Title 1', values: [98, 15, 7, 8], }, { name: 'Title 2', values: [44, 5, 7, 8], }, { name: 'Title 3', values: [5, 7, 8, 9], }, { name: 'Title 4', values: [76, 88, 9, 5], }, ]; const addData: Idata[] = [ { name: 'Title 5', values: [98, 15, 7, 8], }, { name: 'Title 6', values: [44, 5, 7, 8], }, { name: 'Title 7', values: [5, 7, 8, 9], }, { name: 'Title 8', values: [76, 88, 9, 5], }, ]; const App: React.FunctionComponent = () => { const [tag, setTag] = React.useState<Idata[]>(initialData); // 封装添加元素函数,避免重复添加 const handleAdd = (item: Idata) => { if (!tag.find(data => data.name === item.name)) { setTag(prev => [...prev, item]); } }; // 封装移除元素函数,通过唯一name匹配目标 const handleRemove = (itemName: string) => { setTag(prev => prev.filter(data => data.name !== itemName)); }; return ( <React.Fragment> <div className="intial-data"> {tag?.map((inner: Idata) => { // 用唯一的name作为key,比index更可靠 return <div key={inner.name}>{inner.name}</div>; })} </div> <br /> <div> {addData?.map((inner: Idata) => { // 同样用name作为key,避免索引变化导致的渲染异常 return ( <React.Fragment key={inner.name}> <div> {inner.name}{' '} <button onClick={() => handleAdd(inner)}> Add </button> <button onClick={() => handleRemove(inner.name)}> Remove </button> </div> </React.Fragment> ); })} </div> </React.Fragment> ); }; render(<App />, document.getElementById('root'));
关键改动说明
替换
splice为filter:filter会返回全新的数组,不会修改原状态数组,完全符合React状态更新的不可变性原则。我们通过name这个唯一标识过滤目标元素,确保删除的是正确的项。用
name作为元素key:
避免使用数组索引作为key,因为当数组元素顺序变化时,索引会导致React的diff算法出错。这里每个元素的name是唯一的,是理想的key值。封装添加/移除函数:
把逻辑抽成单独的函数,让代码更易读和维护,同时添加了重复添加的判断,避免同一个元素被多次加入tag数组。简化Add按钮逻辑:
直接传递当前循环的inner元素,而非通过addData[index]获取,代码更简洁且不易出错。
这样修改后,你就能精准地添加和移除Title 5到Title 8这些元素,同时不会影响初始的Title 1到Title 4。
内容的提问来源于stack exchange,提问作者Sole

