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

React中如何正确使用setState修改state内的对象?

解决React setState修改嵌套对象时丢失数据的问题

问题现象

调用handleClick修改buttons数组中对象的isHeld属性后,state结构被破坏——原本包含myQuestions和buttons的对象数组,变成了仅包含buttons数组的数组,导致后续渲染时出现Cannot read properties of undefined (reading 'map')错误。

错误原因

你的handleClick函数中嵌套map的逻辑错误:外层prevState.map直接返回了item.buttons.map的结果,没有保留原对象的myQuestions属性,直接把每个问题对象替换成了它的buttons数组,最终整个state变成二维数组,完全丢失原有结构。

修复方案

修改setState的更新逻辑,保留原问题对象的所有属性,仅更新目标按钮的isHeld状态:

  1. 遍历每个问题对象时,先展开原对象(保留myQuestions等属性)
  2. 单独对buttons数组进行遍历,修改匹配id的按钮的isHeld值

修正后的handleClick代码:

function handleClick(e) {
  setState(prevState => prevState.map(questionItem => ({
    // 保留原问题对象的所有属性
    ...questionItem,
    // 仅更新buttons数组中匹配id的项
    buttons: questionItem.buttons.map(button => 
      button.id === e ? {...button, isHeld: !button.isHeld} : button
    )
  })))
}

额外优化点

渲染Quiz组件时,item.buttons.map(item => item)属于冗余操作,直接传递item.buttons即可:

const getGame = state.map(item => <Quiz
  buttons={item.buttons}
  handleClick={(e) => handleClick(e.target.name)}
  questions={item.myQuestions}
/> )

完整修正后代码示例

import React from 'react';
import { v4 as uuidv4 } from 'uuid';

// 假设Quiz组件已定义
function Quiz({ buttons, handleClick, questions }) {
  return (
    <div>
      <h3>{questions}</h3>
      {buttons.map(btn => (
        <button
          key={btn.id}
          name={btn.id}
          onClick={handleClick}
          style={{ backgroundColor: btn.isHeld ? 'lightblue' : 'white' }}
        >
          {btn.use}
        </button>
      ))}
    </div>
  );
}

function App() {
  const [state, setState] = React.useState([]);

  React.useEffect(()=> {
    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 => ({
        myQuestions: item.question,
        buttons: item.incorrect_answers.concat(item.correct_answer).map(item => ({use:item, isHeld:false, id:uuidv4()}))
      }))))
  }, [])

  const getGame = state.map((item, index) => <Quiz
    key={index}
    buttons={item.buttons}
    handleClick={(e) => handleClick(e.target.name)}
    questions={item.myQuestions}
  /> )

  function handleClick(e) {
    setState(prevState => prevState.map(questionItem => ({
      ...questionItem,
      buttons: questionItem.buttons.map(button => 
        button.id === e ? {...button, isHeld: !button.isHeld} : button
      )
    })))
  }

  return (
    <div className="App">
      {getGame}
    </div>
  );
}

export default App;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 07:35:28