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

React使用useState更新数组内对象值时多输入框卡顿如何优化?

优化方案

一、先修复现有代码的bug和冗余逻辑

  1. 你当前addField方法直接修改了原state引用,会导致状态更新异常,同时所有任务的status数组共用同一份引用,修改单个任务的状态会影响所有任务,修复后的新增逻辑:
// 可直接删除无用的taskCount state和对应的useEffect,用test数组长度判断任务数量即可
const [test , setTest] = useState([]);

const schema = {   
  id : 0,
  choice : '',
  questName : '',
  location : '',
  time : '',
  linkedQuestB : '',
  linkedQuestA : '',
  status : [
    {id : 'not_started' , label : 'not_started' , checked : false},
    {id : 'in_progress' , label : 'in_progress' , checked : false},
    {id : 'done' , label : 'done' , checked : false},
  ],
}

const addField = () => {
  // 复制schema时单独复制status数组,避免引用共享
  const newTask = {...schema, id: Date.now(), status: [...schema.status]}
  setTest(prev => [...prev, newTask])
}

// 新增按钮直接调用addField即可
<img 
  src = {plus}
  alt = {'添加任务'}
  onClick = {addField}
/>
  1. 删除更新逻辑里的冗余遍历,对象可直接通过键名取值赋值,不需要遍历所有key匹配:
const updateval = (index, target) => {
  setTest(prev => {
    // 只复制一次数组,仅修改对应下标的数据
    const newList = [...prev]
    newList[index][target.id] = target.value
    return newList
  })
}

二、解决输入卡顿的核心优化:避免全量重渲染

你当前只要一个输入框修改,所有任务的输入组件都会跟着重渲染,是卡顿的核心原因,加组件缓存即可解决:

  1. 用React.memo包裹你的TodoFieldSet和输入框组件,只有props变化时才会重渲染:
const TodoFieldSet = React.memo(({id, update, task}) => {
  // 原有组件逻辑
})
  1. 用useCallback包裹更新函数,避免每次父组件渲染生成新的函数实例导致缓存失效:
const updateval = useCallback((index, target) => {
  setTest(prev => {
    const newList = [...prev]
    newList[index][target.id] = target.value
    return newList
  })
}, [])
  1. 渲染列表时不要用index作为key,用任务的唯一id作为key,避免列表顺序变化时的渲染异常:
{test.map((task, index)=>{ 
  return (
    <TodoFieldSet  
      id={index} 
      key={task.id}
      update={updateval} 
      task={task}
    />
  )
})}

三、超大任务量场景的极致优化

如果需要支持上百个任务同时编辑,可以把数组结构换成对象存储,通过任务id直接匹配对应任务,连数组复制的开销都可以省掉:

// 用对象存储所有任务,key为任务id,value为任务数据
const [taskMap, setTaskMap] = useState({})

const addField = useCallback(() => {
  const newId = Date.now()
  setTaskMap(prev => ({
    ...prev,
    [newId]: {...schema, id: newId, status: [...schema.status]}
  }))
}, [])

const updateval = useCallback((taskId, target) => {
  setTaskMap(prev => ({
    ...prev,
    [taskId]: {
      ...prev[taskId],
      [target.id]: target.value
    }
  }))
}, [])

// 渲染时转数组即可
{Object.values(taskMap).map(task => (
  <TodoFieldSet  
    id={task.id} 
    key={task.id}
    update={updateval} 
    task={task}
  />
))}

内容的提问来源于stack exchange,提问作者findnate

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 02:27:00