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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 09:08:26