React.js中点击Done按钮如何为指定列表项添加删除线样式?
React Todo列表Done按钮无效果的解决方法
你的问题核心在于错误地试图直接修改字符串的style属性,而且违背了React状态驱动渲染的原则——React的UI是由状态决定的,不能直接操作DOM元素来改变样式,必须通过更新状态来触发重新渲染。
问题分析
当前tasks数组存储的是纯字符串,tasks[index]是字符串类型,根本没有style属性,所以tasks[index].style.textDecoration = "line-through"这段代码完全无效。同时,就算你能拿到DOM元素,直接操作DOM也不是React的正确做法,状态变化才应该是UI更新的唯一触发源。
解决方案步骤
- 修改任务数据结构:把
tasks数组的元素从字符串改成对象,每个对象包含任务文本和完成状态(比如{ text: '任务内容', isDone: false })。 - 更新添加任务逻辑:添加新任务时,存入包含文本和完成状态的对象。
- 重写Done按钮的点击逻辑:通过更新状态来切换对应任务的完成状态。
- 根据状态渲染样式:在渲染任务时,根据完成状态动态添加删除线样式。
修改后的完整代码
function Todo(){ // 修改tasks的初始状态为存储对象的数组 const [tasks, setTasks] = useState([]); const [newTask, setNewTask] = useState(""); function handleChange(event){ setNewTask(event.target.value); } function updateTodo(){ if(newTask.trim() !== ""){ // 添加新任务时存入包含text和isDone的对象 setTasks(prevTasks => [...prevTasks, { text: newTask, isDone: false }]); setNewTask(""); } } function deleteTask(index){ const updatedTasks = tasks.filter((_, i) => i !== index); setTasks(updatedTasks); } function toggleDone(index){ // 遍历tasks,翻转对应索引任务的isDone状态 const updatedTasks = tasks.map((task, i) => { if(i === index){ return { ...task, isDone: !task.isDone }; } return task; }); setTasks(updatedTasks); } return( <div id="main"> <h1>To-Do List</h1> <div id="add"> <input type="text" id="add_item" placeholder='Enter your task' value={newTask} onChange={handleChange} /> <input type="button" id="add_button" onClick={updateTodo} value="Submit" /> </div> <div id="list"> <ol> {tasks.map((task, index) => ( <li key={index}> {/* 根据isDone状态动态设置样式 */} <div className="list_item" style={{ textDecoration: task.isDone ? "line-through" : "none" }} > {task.text} </div> <div className="button_container"> <button className="delete" onClick={() => deleteTask(index)}>Delete</button> <button className="done" onClick={() => toggleDone(index)}>Done</button> </div> </li> ))} </ol> </div> </div> ) }
关键修改点说明
- 数据结构变更:用
{ text: '', isDone: false }对象存储任务,让每个任务自带完成状态标记。 - toggleDone函数:通过
map方法创建新数组,避免直接修改原状态数组(React状态是不可变的),翻转对应任务的isDone值后更新状态。 - 动态样式渲染:在
list_item的div上,通过内联样式style={{ textDecoration: task.isDone ? "line-through" : "none" }}根据完成状态决定是否显示删除线。
额外优化建议
- 不要用索引作为
key:如果任务有删除操作,索引会发生变化,可能导致渲染异常。可以给每个任务生成唯一ID(比如用Date.now()或者第三方库如uuid),把ID作为key值。
内容的提问来源于stack exchange,提问作者Abhrajit Saha
相关产品推荐
相关产品推荐

