You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React useState删除数组元素异常:选中项未被删除问题求助

React useState数组删除异常问题解决

问题现象

在React项目中使用useState管理benefits数组对象时,执行指定索引元素的删除操作后,被删除的并非选中项,总是最后一个元素被删除。调试显示splice方法运行正常,选中的索引也正确,但更新useState数组后,选中索引的删除操作不生效。例如选中删除orange,实际被删除的却是最后一项guava。

问题代码

useState定义

const [benefits, setBenefits] = useState([{name:''}])

输入框 onChange 处理函数

const handlerDescription = (index,e) =>{
    e.preventDefault();
    let temp = [...benefits]
    temp[index] = e.target.value
    setBenefits(temp)
}

删除行处理函数

const handlerCloseRow = (index) => {
    const newItems = [...benefits]; // 创建数组副本
    newItems.splice(index, 1); // 删除指定索引的元素
    setBenefits(newItems); // 更新状态
};

添加行处理函数

const handlerAddRow = (e) =>{
    e.preventDefault();
    setBenefits([...benefits,{
        name:''
    }])
}

渲染代码

<section>
    <label>
    Description
    </label>
    {benefits.map((benefit,index)=>(
        <div key={index} className="mb-4">
            <Input onChange={(e)=>handlerDescription(index,e)} value={benefits?.name} type="text" />
            <button onClick={(e)=>handlerCloseRow(index,benefit,e)}>close</button>
        </div>
    ))}
    <div onClick={handlerAddRow}>
        <button className="text-3xl"/><span>Add Row</span>
    </div>
</section>

问题根源

  1. key使用index导致渲染混乱:map循环时用数组索引作为key,当数组元素被删除后,后续元素的索引会前移,React会复用之前的DOM节点,导致状态与DOM节点不匹配,看起来像是删除了最后一个元素。
  2. 输入框值绑定错误:value={benefits?.name}错误地绑定了整个数组的name属性(数组本身没有该属性,实际值为undefined),应该绑定当前循环项的benefit.name。
  3. 状态更新逻辑错误:handlerDescription中直接用字符串替换数组元素,但benefits的每一项是对象,应该修改对象的name属性而非替换整个元素。

修复方案

1. 为数组元素添加唯一标识,替换index作为key

修改添加行函数,给每个元素生成唯一id(这里用时间戳示例):

const handlerAddRow = (e) =>{
    e.preventDefault();
    setBenefits([...benefits,{
        id: Date.now(), // 生成唯一id
        name:''
    }])
}

渲染时使用元素的id作为key:

{benefits.map((benefit, index) =>(
    <div key={benefit.id} className="mb-4">
        <Input onChange={(e)=>handlerDescription(index,e)} value={benefit.name} type="text" />
        <button onClick={()=>handlerCloseRow(index)}>close</button>
    </div>
))}

2. 修正输入框值绑定

将value={benefits?.name}改为value={benefit.name},确保每个输入框对应正确的元素值:

<Input onChange={(e)=>handlerDescription(index,e)} value={benefit.name} type="text" />

3. 修正状态更新逻辑

在handlerDescription中正确修改对象的name属性,而非替换整个元素:

const handlerDescription = (index,e) =>{
    e.preventDefault();
    let temp = [...benefits];
    // 复制当前元素对象并修改name属性
    temp[index] = {...temp[index], name: e.target.value};
    setBenefits(temp);
}

4. 优化删除函数(可选,避免闭包问题)

当状态更新依赖于之前的状态时,使用函数式更新确保获取最新的state:

const handlerCloseRow = (index) => {
    setBenefits(prevBenefits => {
        const newItems = [...prevBenefits];
        newItems.splice(index, 1);
        return newItems;
    });
};

内容的提问来源于stack exchange,提问作者Ray Paras

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 07:28:23