我正在使用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()
迭代,因为您知道这些问题没有改变。