如何使用setState修改含嵌套对象数组的React状态?
问题与解决方案
核心问题
- 无法正确使用
setState修改嵌套对象数组中指定元素的value值,当前实现会错误地将所有元素的value设为true - 子组件通过
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
相关产品推荐
相关产品推荐

