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

如何使用setState修改含嵌套对象数组的React状态?

问题与解决方案

核心问题

  1. 无法正确使用setState修改嵌套对象数组中指定元素的value值,当前实现会错误地将所有元素的value设为true
  2. 子组件通过id触发点击事件后,如何精准修改对应状态

你的代码

React.useEffect(()=> {
  if(start === true){
    
    fetch("https://opentdb.com/api.php?amount=5&category=27&difficulty=easy&type=multiple")
      .then(res => res.json())
      
      .then(data => setState(data.results.map(item =>
        ({selectedQuestion: "",
          buttons: item.incorrect_answers.concat(item.correct_answer).map(item => 
            ({use: item, value: false, id: uuidv4()})),
          questions: item.question   
          
        }))))
  }
}, [start])

function startGame () {  
  setStart(prevState => !prevState)
}

const myButtons = state.map(function(item) { 
  return (<Quiz 
    key={uuidv4()}
    buttons={item.buttons}
    question = {item.questions}
    handleClick ={(event) =>handleClick(event.target.id)}

  /> ) 
})

console.log(state)
let myFlat = state.map(item => item.buttons.map(item => item.id))
let finalFlat = myFlat.flat()

function handleClick (event) {
  for(let i = 0; i<finalFlat.length; i++){
    if(finalFlat[i] === event){
      setState(item => item.map(item =>({
        ...item, value:true
      })))
    }
  }
}

修复方案

1. 修正handleClick函数,精准修改对应元素的value

你的当前逻辑会遍历所有元素并统一设置value: true,正确的做法是逐层遍历匹配id,只修改目标元素:

function handleClick(buttonId) {
  // 使用函数式更新确保拿到最新状态
  setState(prevState => 
    prevState.map(question => ({
      // 保留question的原有属性
      ...question,
      // 遍历buttons数组,找到目标id修改value
      buttons: question.buttons.map(button => 
        button.id === buttonId 
          ? { ...button, value: true } // 匹配到id则修改value
          : button // 未匹配则返回原对象
      )
    }))
  );
}

2. 移除冗余的扁平化id数组

你之前的myFlat和finalFlat以及for循环完全不需要,上面的handleClick直接通过状态内部的id匹配即可完成修改。

3. 修复组件key的问题

不要用uuidv4()作为组件的key,每次渲染都会生成新key,导致组件频繁卸载重建。给每个question添加唯一id,用它作为key:

// 在fetch初始化状态时给每个question添加id
.then(data => setState(data.results.map(item => ({
  id: uuidv4(), // 新增question唯一id
  selectedQuestion: "",
  buttons: item.incorrect_answers.concat(item.correct_answer).map(item => ({
    use: item,
    value: false,
    id: uuidv4()
  })),
  questions: item.question   
}))))

// 渲染Quiz组件时使用question的id作为key
const myButtons = state.map(function(item) { 
  return (<Quiz 
    key={item.id}
    buttons={item.buttons}
    question={item.questions}
    handleClick={(event) => handleClick(event.target.id)}
  /> ) 
})

4. 子组件按钮的id绑定

确保子组件Quiz中,每个按钮的id属性正确绑定到button.id,比如:

// Quiz组件内部示例
function Quiz({ buttons, question, handleClick }) {
  return (
    <div>
      <p>{question}</p>
      {buttons.map(button => (
        <button 
          key={button.id}
          id={button.id}
          onClick={handleClick}
          style={{ backgroundColor: button.value ? 'green' : 'white' }}
        >
          {button.use}
        </button>
      ))}
    </div>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 06:54:22