将状态设置为与嵌套的.map函数反应是否可行



我正在使用react组件函数开发一个简单的多选问答应用程序。

每个问题都有2或4个可能的答案,其中我在嵌套对象/数组中配置了数据,示例如下:

{
question: 'what country is....',
id: nanoid(),
answers: 
[{
answer: 'Egypt',
id: nanoid(),
isCorrect: true,
isChecked: false
},
{
answer: 'Greece',
id: nanoid(),
isCorrect: false,
isChecked: false
},
{......}

我的问题是,当我想翻转"isChecked"属性时(当有人单击相应的按钮时(,我需要遍历对象,然后遍历"answers"数组,但我无法正确设置状态,我尝试了嵌套映射方法,我也尝试了嵌套for循环,但无论我尝试什么,都无法获得所需的结果。

当有嵌套的对象和数组来正确可靠地设置State时,什么是简单的方法?

这是下面的代码

App.js

import React from 'react'
import Questions from './Questions'
import { nanoid } from 'nanoid'
import { decode } from 'he'
export default function App() {
const [tempState, setTempState] = React.useState(true)
const [data, setData] = React.useState([])

React.useEffect(() => {
fetch("https://opentdb.com/api.php?amount=5&category=9&difficulty=medium")
.then(res => res.json())
.then(info => stateFormat(info.results))
}, [])

function stateFormat(rawData) {
// console.log(rawData)
let correctAnswers = [];
for (let i = 0; i < rawData.length; i++) {
correctAnswers.push({
question: rawData[i].question,
id: nanoid(),
answers: [{
answer: rawData[i].correct_answer,
id: nanoid(),
isCorrect: true,
isChecked: false
}]
})
if (rawData[i].incorrect_answers.length > 2) {
for (let j = 0; j < 3; j++) {
correctAnswers[i].answers.push({
answer: rawData[i].incorrect_answers[j],
id: nanoid(),
isCorrect: false,
isChecked: false
})
}
} else {
correctAnswers[i].answers.push({
answer: rawData[i].incorrect_answers[0],
id: nanoid(),
isCorrect: false,
isChecked: false
})
}
}
setData(correctAnswers)
console.log(data)
}

function handleChange(id) {
setData(prev => {
for(let i = 0; i < prev.length; i++) {
for(let j = 0; j < prev[i].answers.length; j++) {
// console.log(prev[i].answers[j])
if(prev[i].answers[j].id === id) {
console.log({...prev[i].answers[j], isChecked: !prev[i].answers[j].isChecked})
return {...prev[i].answers[j], isChecked: !prev[i].answers[j].isChecked}
} else {
// return {...prev[i].answers[j]}
}
}
}
})



}

// function handleChange(id) {
//   setData(prev => prev.map(item => {
//    return (item.answers.map(button => {
//       return button.id === id ?
//       { ...button, isChecked: !button.isChecked } :
//       button
//     }))

//   }))
// }

const questionElements = data.map(item => (
<Questions
key={item.id}
question={item.question}
answers={item.answers}
handleChange={handleChange}
/>
))


return (
<main>
<img className="blob--top"
src={require('./blobs.png')}
/>
<img className="blob--bottom"
src={require('./blobs1.png')}
/>
{tempState ?
<div className="quiz--container">
<div>
{questionElements}
<button className="game--check button">Check answers</button>
</div>
</div> :
<>
<div className="title--container">
<div className="title--init">
<h2 className="title--header">Quizzical</h2>
<h4 className="title--subheader">A battle of the brains</h4>
<button className="game--start button"
onClick={() => setTempState(!tempState)}
>
Start quiz</button>
</div>
</div>
</>
}
</main>
);
}

问题.js

import React from 'react'
import { decode } from 'he'
export default function Questions(props) {

// console.log(props)
const answerButton = props.answers.map(item => (
<button
isCorrect={item.isCorrect}
isChecked={item.isChecked}
id={item.id}
style={{backgroundColor: item.isChecked ? "#D6DBF5" : ""}}
onClick={() => props.handleChange(item.id)}>{decode(item.answer)}
</button>
))
return (
<div className="question--container">
<h4>{decode(props.question)}</h4>
<div className="question--items">
{answerButton}
</div>
<img src={require('./Line13.png')} />
</div>
)
}

问题是我的handleChange(id(函数,如何返回合适的对象?

您的.map()方法非常接近,您只需要将内部.map()封装在一个对象中。对象应该包含所有item属性,您可以通过用...item扩展当前item来创建这些属性,然后将answer属性覆盖为映射的answers数组:

function handleChange(id) {
setData(prev => prev.map(item => {
return {
...item,
answers: item.answers.map(button => {
return button.id === id
? { ...button, isChecked: !button.isChecked} 
: button
})
};
}));
}

使用箭头函数,您可以省略函数体{},因此如果您所做的只是从函数体内部返回,则可以省略return。所以上面可以重写为:

function handleChange(id) {
setData(prev => prev.map(item => ({
...item,
answers: item.answers.map(button => button.id === id
? { ...button, isChecked: !button.isChecked} 
: button
)
})));
}

注意,如果你想让你的代码更有效率,你也可以在调用handleChange()时传递问题id,这将允许你在外部.map()中添加一个附加条件,这样你只在迭代正在回答的问题时执行内部.map(),对于所有其他问题,您可以跳过answers数组上的内部.map()迭代,因为您知道这些问题没有改变。

最新更新