React setState异常:点击Save按钮后Edit函数触发,无法退出编辑模式
编辑任务后点击Save按钮无法退出编辑模式的问题
我正在开发一款生产力工具网站,支持用户添加、编辑和删除任务,但遇到了编辑完成后保存按钮的bug。点击Save按钮时,handleSaveTask函数会被调用,但同时handleEditTask函数也被触发,将isEditing状态设回true,导致始终停留在编辑模式。
以下是我的代码:
import React, { useState } from 'react'; import './TaskList.css' interface taskList { id: number; name: string; start: number; end: number; } interface TaskListProps { tasks: taskList[]; onChangeTask: Function; onDeleteTask: Function; } interface TaskProps { task: taskList; onChange: Function; onDelete: Function; } export const TaskList: React.FC <TaskListProps> = ({tasks, onChangeTask, onDeleteTask}) => { return ( <div className='center'> <h2 className='tasksTitle'>Tasks</h2> <div className='taskTitle'> <p className='taskTitle1'>Task Name</p> <p className='taskTitle2'>Range</p> </div> {tasks.map((task) => ( <Task key={task.id} task={task} onChange={onChangeTask} onDelete={onDeleteTask} /> ))} </div> ); } const Task: React.FC <TaskProps> = ({task, onChange, onDelete}) => { const [isEditing, setIsEditing] = useState(false); let taskContent; const handleEditTask = () => { console.log("in Handle Edit Task"); setIsEditing(true); } const handleSaveTask = () => { console.log("in Handle Save"); setIsEditing(false); } if (isEditing) { taskContent = ( <div id='editTask'> <input value={task.name} className="input inputName" onChange={(e) => { onChange({ ...task, name: e.target.value, }); }} /> <input value={task.start} className="input inputNumber" onChange={(e) => { onChange({ ...task, start: e.target.value, }); }} /> <input value={task.end} className="input inputNumber" onChange={(e) => { onChange({ ...task, end: e.target.value, }); }} /> <button className="button buttonPrimary addButton" onClick={() => handleSaveTask()}>Save</button> </div> ); } else { taskContent = ( <> <div className='taskContent'> <p className='taskContentItem1'>{task.name}</p> <p className='taskContentItem2'>{task.start}-{task.end}</p> <div className='taskContentItem3'> <button className='button buttonPrimary' onClick={() => handleEditTask()}>Edit</button> <button className="button buttonSecondary" onClick={() => onDelete(task.id)}>X</button> </div> </div> </> ); } return ( <> <div className='center' > <label className='taskList'> <div className='taskListItem1'> {taskContent} </div> </label> </div> </> ); }
点击Save按钮后,控制台会同时打印出in Handle Save和in Handle Edit Task。我尝试添加依赖isEditing的useEffect钩子,但引发了无限循环。
原因分析
问题出在你把taskContent放在了<label>标签内部。在HTML中,<label>的点击事件会冒泡传递,且该标签原本用于关联表单控件,此处无关联控件的情况下,点击内部的Save按钮时,事件冒泡到外层<label>后,会间接触发原本隐藏的Edit按钮的点击事件,导致handleEditTask被意外调用,把isEditing重新设为true。
解决方法
直接移除包裹taskContent的<label>标签即可,该标签在此处没有实际作用,反而引发了事件冒泡问题。
修改后的Task组件返回部分代码:
return ( <> <div className='center' > <div className='taskListItem1'> {taskContent} </div> </div> </> );
额外优化建议
- 给
start和end对应的输入框添加type="number"属性,限制输入内容为数字:
<input type="number" value={task.start} className="input inputNumber" ... />
- 更新
start和end值时,将字符串转为数字,避免类型不匹配:
onChange({ ...task, start: Number(e.target.value), });
内容的提问来源于stack exchange,提问作者lili4x4
相关产品推荐
相关产品推荐

