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

React Todo列表问题:点击单个完成按钮却标记全部Todo为已完成

问题排查与解决方案

问题根源

你当前使用了一个全局的doneTask布尔状态来控制所有Todo项的完成样式,所有Todo的className都绑定这个单一状态。只要调用setDoneTast(true),所有Todo都会触发样式变化,这就是点击任意Done按钮全列表变已完成的原因。

正确实现思路

每个Todo项需要独立的完成状态,因此todos数组的每一项应该是包含文本内容和完成状态的对象,而不是单纯的字符串。

修改步骤及完整代码

  1. 调整Todo数据结构:将todos数组的元素改为对象,包含text(待办内容)和done(完成状态)两个属性
  2. 移除全局doneTask状态:不再需要单一全局状态,改为每个Todo自己管理完成状态
  3. 更新添加Todo逻辑:添加时创建包含text和done的对象
  4. 修改完成状态切换函数:通过map遍历数组,找到对应ID的Todo并切换其done状态
  5. 更新渲染逻辑:根据当前Todo项的done属性决定是否添加完成样式

修改后的完整代码:

import { useState } from "react";
import "./App.scss";

function App() {
  const [val, setVal] = useState("");
  // todos数组元素改为对象,包含text和done属性
  const [todos, setTodos] = useState([]);

  const addTodos = (e) => {
    if (!val.trim()) return;
    e.preventDefault();
    // 添加新Todo时,默认done为false(未完成)
    setTodos([...todos, { text: val, done: false }]);
    setVal("");
  };

  const handleDelete = (id) => {
    setTodos(todos.filter((_, key) => key !== id));
  };

  const handleDoneTask = (id) => {
    // 遍历数组,切换对应ID的Todo的done状态
    setTodos(todos.map((todo, key) => {
      if (key === id) {
        return { ...todo, done: !todo.done };
      }
      return todo;
    }));
  };

  return (
    <div className="App">
      <form onSubmit={addTodos}>
        <input
          onChange={(e) => setVal(e.target.value)}
          value={val}
          type="text"
          placeholder="输入待办事项"
        />
        <button type="submit">Add</button>
      </form>
      <ul>
        {todos.map((todo, key) => (
          <div className="arrange" key={key}>
            {/* 根据当前Todo的done属性决定样式 */}
            <li className={todo.done ? "doneTask" : ""}>{todo.text}</li>
            <a onClick={() => handleDoneTask(key)}>Done</a>
            <a onClick={() => handleDelete(key)}>Cancel</a>
          </div>
        ))}
      </ul>
    </div>
  );
}

export default App;

CSS部分保持不变:

.doneTask {
  text-decoration: line-through!important;
}

额外提示

  • 尽量避免用数组索引(key)作为元素的key属性,如果Todo项有删除操作,索引会变化可能导致渲染异常,建议给每个Todo生成唯一ID(比如用Date.now()或者第三方库uuid)
  • 输入判断用!val.trim()代替val == "",可以过滤纯空格的无效输入

内容的提问来源于stack exchange,提问作者jj-ammar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 21:47:03