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

React Todo列表事件委托删除失效:为何文本值匹配却无法过滤?

为什么通过innerText匹配无法正确删除Todo项?

我用事件委托给ul绑定点击事件实现Todo删除功能,但遇到奇怪的问题:明明toDo和e.target.parentNode.children[0].innerText看起来值一样,比如都是"study",类型也都是字符串,但toDo != e.target.parentNode.children[0].innerText始终没法正确过滤掉目标项,导致点击删除按钮后对应的Todo没被移除。

import './styles.css';
import React, {useState} from 'react';

export default function App() {
  const [toDoList, setToDoList] = useState([]);
  const [value, setValue] = useState([]);

  const addToDo = () => {
    let copyToDoList = [...toDoList];
    setToDoList([...copyToDoList, value]);
    setValue("");
  }

  const deleteToDo = (e) => {
    let copyToDoList = [...toDoList];
    let filteredList = copyToDoList.filter((toDo) => { 
      return toDo != e.target.parentNode.children[0].innerText})
    console.log(filteredList)
    setToDoList(filteredList);
  }

  const handleChange = (e) => {
    setValue(e.target.value);
  }

  return (
    <div>
      <h1>Todo List</h1>
      <div>
        <input value={value} onChange={handleChange} type="text" placeholder="Add your task" />
        <div>
          <button onClick={addToDo}>Submit</button>
        </div>
      </div>
      <ul onClick={deleteToDo}>
        {toDoList.map((toDo, idx) => {
          return(
            <li>
              <span>{toDo} </span>
              <button>Delete</button>
            </li>
            )
        })}
      </ul>
    </div>
  );
}

问题原因

  • 隐藏的空格导致字符串不匹配:你渲染Todo的代码里,<span>{toDo} </span>的{toDo}后面多了一个空格,这会让innerText的实际值是"study "(末尾带空格),但你存在状态里的toDo是"study"(无空格)。控制台打印时这个空格不会被明显标注,看起来两者相同,但实际字符串并不相等,过滤条件自然不生效。
  • 事件委托的范围问题:点击ul内部的任何元素(比如li、span)都会触发deleteToDo函数,只有点击Delete按钮时,e.target.parentNode才是对应的li;如果点击的是span或li本身,e.target.parentNode可能指向错误的元素,导致获取的innerText完全不对。
  • 状态初始化错误:value的初始状态设成了数组[],但输入框需要的是字符串类型,虽然这不是当前删除问题的直接原因,但可能引发其他异常。

解决方案

1. 去掉多余空格(快速修复)

把<span>{toDo} </span>改成<span>{toDo}</span>,让innerText和状态里的toDo完全一致。

2. 用trim()处理字符串

如果担心后续还有空格问题,可以在比较时给innerText做trim处理,去除两端的空白字符:

let filteredList = copyToDoList.filter((toDo) => { 
  return toDo !== e.target.parentNode.children[0].innerText.trim()
})

3. 用索引/唯一ID删除(推荐)

完全避免字符串匹配的坑,给每个Todo项绑定唯一标识,点击时直接根据标识过滤:

  • 修改渲染逻辑,给按钮添加data-index属性存索引:
{toDoList.map((toDo, idx) => {
  return(
    <li key={idx}>
      <span>{toDo}</span>
      <button data-index={idx}>Delete</button>
    </li>
  )
})}
  • 修改删除函数,只处理按钮点击事件,并通过索引过滤:
const deleteToDo = (e) => {
  // 只响应Delete按钮的点击
  if (e.target.tagName.toLowerCase() !== 'button') return;
  const targetIndex = parseInt(e.target.dataset.index);
  setToDoList(prevList => prevList.filter((_, idx) => idx !== targetIndex));
}

4. 修复状态初始化错误

把const [value, setValue] = useState([]);改成const [value, setValue] = useState("");,保证输入框的初始值是正确的字符串类型。

内容的提问来源于stack exchange,提问作者Judoboy Alex

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 08:10:23