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

React待办列表li与嵌套删除按钮onClick事件冲突导致样式错误如何解决

问题根因

你的异常是两个问题叠加导致的:

  • 事件冒泡:删除按钮嵌套在<li>内部,点击按钮的事件会向上冒泡触发父级<li>的点击事件,在删除逻辑执行后,当前ListItem组件的clickedOn状态会被误修改
  • 用数组索引作为key:删除条目后数组索引发生偏移,React会复用索引匹配的旧ListItem组件,导致旧组件的clickedOn状态被误用到新的相邻条目上

最优修正方案

步骤1:阻止删除按钮的事件冒泡

在ListItem的删除按钮点击回调中调用event.stopPropagation(),阻断事件向上传递,避免触发父级<li>的点击事件。

步骤2:替换索引key为唯一标识

调整待办项的数据结构,为每个待办项生成唯一ID,用ID作为ListItem的key,避免组件状态错用。

修改后代码

App.js

import React, { useState } from "react";
import ListItem from "./ListItem";

function App() {
  const [inputText, setInputText] = useState("");
  const [items, setItems] = useState([]);

  function handleChange(event) {
    const newValue = event.target.value;
    setInputText(newValue);
  }

  function addItem() {
    setItems((prevItems) => {
      // 每个待办项存为带唯一id的对象,用时间戳做简单唯一标识
      return [...prevItems, {
        id: Date.now(),
        content: inputText
      }];
    });
    setInputText("");
  }

  function deleteItem(id) {
    setItems((prevItems) => {
      // 按id过滤删除项,不再用索引
      return prevItems.filter((item) => item.id !== id);
    });
  }

  return (
    <div className="container">
      <div className="heading">
        <h1>To-Do List</h1>
      </div>
      <div className="form">
        <input onChange={handleChange} type="text" value={inputText} />
        <button onClick={addItem}>
          <span>Add</span>
        </button>
      </div>
      <div>
        <ul>
          {items.map((todoItem) => (
            <ListItem
              key={todoItem.id}
              id={todoItem.id}
              item={todoItem.content}
              delete={deleteItem}
            />
          ))}
        </ul>
      </div>
    </div>
  );
}

export default App;

ListItem.js

import React, { useState } from "react";

function ListItem(props) {
  const [clickedOn, setClickedOn] = useState(false);

  function handleClick() {
    setClickedOn((prevValue) => !prevValue);
  }

  return (
    <div>
      <li
        onClick={handleClick}
        style={{ textDecoration: clickedOn ? "line-through" : "none" }}
      >
        {props.item}
        <button
          onClick={(e) => {
            // 阻止事件冒泡
            e.stopPropagation();
            props.delete(props.id);
          }}
          style={{ float: "right" }}
        >
          <span>Del</span>
        </button>
      </li>
    </div>
  );
}

export default ListItem;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 13:45:03