React Hooks待办列表异常:多任务score值相同求助
解决待办项score全局同步的问题
嘿,我来帮你梳理下问题出在哪,以及怎么解决~
问题根源
你目前把speed、urgency、score这些状态都放在了父组件ToDo里,这意味着所有待办项共享同一组状态值。不管你修改哪一个待办项的下拉框,都会更新父组件的全局状态,然后所有待办项的score都会用这同一个全局的speed和urgency计算,自然所有项的score就都一样了。
解决方案
我们需要让每个待办项拥有独立的状态数据。具体来说,把toDo数组里的元素从单纯的字符串,改成包含任务内容、speed、urgency、score的对象,这样每个待办项的属性都是独立的。同时修改下拉框的更新逻辑,只更新当前待办项对应的属性,并重新计算它的score。
修改后的完整代码
function ToDo(){ const [ input, setInput ] = React.useState('') // 现在toDo数组里存的是对象,每个对象包含独立的任务数据 const [ toDo, setToDo ] = React.useState([]) // 新增待办项时,存入包含默认值的对象 const handleAddTask = () => { if (!input.trim()) return; // 避免空任务 const newTask = { id: Date.now(), // 用时间戳做唯一key,比index更可靠 task: input, speed: 1, // 默认slow urgency: 1, // 默认non-urgent score: 2 // 默认score=1+1 } setToDo([...toDo, newTask]) setInput('') } // 更新speed的逻辑:找到对应任务,更新speed并重新计算score const handleUpdateSpeed = (taskId, newSpeed) => { setToDo(toDo.map(task => { if (task.id === taskId) { const updatedScore = newSpeed + task.urgency return {...task, speed: newSpeed, score: updatedScore} } return task })) } // 更新urgency的逻辑:找到对应任务,更新urgency并重新计算score const handleUpdateUrgency = (taskId, newUrgency) => { setToDo(toDo.map(task => { if (task.id === taskId) { const updatedScore = task.speed + newUrgency return {...task, urgency: newUrgency, score: updatedScore} } return task })) } // 删除任务逻辑 const handleDeleteTask = (taskId) => { setToDo(toDo.filter(task => task.id !== taskId)) } // 按score降序排序 const handleSort = () => { const sortedTasks = [...toDo].sort((a, b) => b.score - a.score) setToDo(sortedTasks) } return( <div> <h2>List of things to do</h2> <input value={ input } onChange={ (e) => setInput( e.target.value ) }/> <button onClick={handleAddTask}>Add </button> <ul> { toDo.map(( task ) => { return ( <li key={task.id}> {task.task}<br/> {/* 更新当前任务的speed */} <select value={task.speed} onChange={(e) => handleUpdateSpeed(task.id, Number(e.target.value))} > <option value={1}>slow</option> <option value={2}>medium</option> <option value={3}>fast</option> </select><br/> {/* 更新当前任务的urgency */} <select value={task.urgency} onChange={(e) => handleUpdateUrgency(task.id, Number(e.target.value))} > <option value={1}>non-urgent</option> <option value={3}>urgent</option> </select> {/* 显示当前任务的score */} <span style={{marginLeft: '10px'}}>Score: {task.score}</span> <span onClick={() => handleDeleteTask(task.id)} style={{marginLeft: '10px', cursor: 'pointer', color: 'red'}} > [Delete] </span> </li> ) }) } </ul> <button onClick={handleSort}>Sort!</button> </div> ) } ReactDOM.render(<ToDo/>, document.getElementById('app'));
关键改动说明
- 数据结构调整:把
toDo数组的元素从字符串改为对象,每个对象存储独立的task、speed、urgency、score,还有唯一的id(避免用index作为key带来的渲染问题)。 - 状态更新逻辑:修改下拉框的
onChange事件,只更新当前点击的待办项对应的属性,同时重新计算该任务的score。 - 排序逻辑修正:之前的排序是直接比较字符串(会得到NaN),现在改为比较每个任务对象的
score字段。 - 删除逻辑优化:用
filter替代splice,更符合React的不可变数据原则,同时用唯一id定位要删除的任务。
这样每个待办项的score就会独立计算和更新,不会再出现所有项score相同的问题啦~
内容的提问来源于stack exchange,提问作者Marco Mazzai
相关产品推荐
相关产品推荐

