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

React Todo应用删除后输入报错:Failed to execute 'removeChild' on 'Node'

问题修复:Todo应用删除后输入报错的解决办法

你的问题出在混合使用React状态管理和手动DOM操作,加上state更新方式错误、key值不合理这几个点,导致React虚拟DOM和真实DOM不同步,输入时触发重渲染就会抛出removeChild错误。下面是具体问题分析和修复方案:

核心问题分析

  • 手动DOM操作干扰React渲染:你直接调用child.parentElement.remove()删除了DOM节点,但React的状态里这个元素还没更新,当输入框触发重渲染时,React会尝试操作已经被你手动删除的节点,导致报错。
  • 直接修改原state数组:items.splice(...)是修改原数组,然后setitems(items),React因为数组引用没变化,不会正确触发重渲染,但你又手动删了DOM,导致虚拟DOM和真实DOM完全脱节。
  • Key值重复风险:用任务内容e作为key,如果添加相同的任务,key会重复,React无法正确区分每个列表项,渲染逻辑混乱。
  • 索引获取错误:items.indexOf(e)在有重复任务时,只会拿到第一个匹配项的索引,删除操作会搞错对象,同时生成的delete id也会重复。

修复方案

1. 完全依赖React状态管理,移除手动DOM操作

React的核心是状态驱动视图,删除操作只需要更新items状态,剩下的渲染交给React处理,不需要手动操作DOM。

2. 正确更新state数组(保持不可变性)

不要直接修改原数组,而是创建新数组。可以用filter方法过滤掉要删除的元素,或者用扩展运算符+slice来生成新数组。

3. 给列表项设置唯一key

不要用任务内容当key,最好给每个任务加唯一id(比如用时间戳或者递增数字),确保每个列表项的key唯一。

4. 避免用indexOf定位元素

如果用唯一id,直接通过id查找元素;如果暂时不想加id,也可以在map的时候拿到索引,直接用索引删除(但不推荐,因为列表顺序变化时会有问题,最好还是加id)。

修复后的完整代码

import { useState } from 'react'
import "./todo.css"

function Todo() {
    const [value, setValue] = useState("")
    const [items, setItems] = useState([])

    function handleClick() {
        // 给每个任务添加唯一id,用时间戳保证唯一性
        if (value.trim()) {
            setItems([...items, { id: Date.now(), content: value }])
            setValue("")
        }
    }

    function handleChange(e) {
        setValue(e.target.value)
    }

    function handleDelete(taskId) {
        // 用filter生成新数组,过滤掉要删除的任务
        setItems(items.filter(item => item.id !== taskId))
    }

    return (
        <>
            <div className='container'>
                <h1 id='mainhead'>Todo App</h1>
            </div>

            <div className='container1'>
                <input onChange={handleChange} value={value} placeholder='Enter a task' type="text" />
                <button onClick={handleClick}>Add Item</button>
            </div>

            {items.length > 0 ? items.map((item, index) => (
                <div className='item' key={item.id}>
                    <label>Task {index + 1}:</label> {item.content}
                    <button 
                        style={{float:"right" , backgroundColor:"red" , color:"white" , width:"80px" , height:"30px"}}
                        onClick={() => handleDelete(item.id)}
                    >
                        Delete
                    </button>
                </div>
            )) : null}
        </>
    )
}

export default Todo

额外优化点

  • 添加了value.trim()判断,避免添加空任务
  • 把删除逻辑抽成单独的handleDelete函数,代码更清晰
  • 用解构赋值和扩展运算符保持state不可变性,符合React最佳实践

内容的提问来源于stack exchange,提问作者Anas Sohail

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 09:12:51