React Todo列表问题:点击单个完成按钮却标记全部Todo为已完成
问题排查与解决方案
问题根源
你当前使用了一个全局的doneTask布尔状态来控制所有Todo项的完成样式,所有Todo的className都绑定这个单一状态。只要调用setDoneTast(true),所有Todo都会触发样式变化,这就是点击任意Done按钮全列表变已完成的原因。
正确实现思路
每个Todo项需要独立的完成状态,因此todos数组的每一项应该是包含文本内容和完成状态的对象,而不是单纯的字符串。
修改步骤及完整代码
- 调整Todo数据结构:将
todos数组的元素改为对象,包含text(待办内容)和done(完成状态)两个属性 - 移除全局
doneTask状态:不再需要单一全局状态,改为每个Todo自己管理完成状态 - 更新添加Todo逻辑:添加时创建包含
text和done的对象 - 修改完成状态切换函数:通过
map遍历数组,找到对应ID的Todo并切换其done状态 - 更新渲染逻辑:根据当前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
相关产品推荐
相关产品推荐

