I am trying to change the isSelected property on a click event, but I am receiving "Cannot read properties of undefined". Also, the state after the event is undefined.
Here is the code:
App.js
function App() {
const [quiz, setQuiz] = React.useState(false)
const [quizData, setQuizData] = React.useState([])
React.useEffect(() => {
async function getQuizData() {
const res = await fetch("https://opentdb.com/api.php?amount=5&type=multiple")
const data = await res.json()
setQuizData(formatData(data.results))
}
getQuizData()
}, [])
function formatData(questions) {
let formatedData = questions.map(item => {
return {
id: nanoid(),
question: item.question,
correctAnswer: item.correct_answer,
answers: shuffleAnswers([...item.incorrect_answers, item.correct_answer])
}
})
return formatedData
}
function shuffleAnswers(answers) {
let randomAnswers = [...answers].sort((a, b) => Math.random() - 0.5)
let randomAnswerList = randomAnswers.map(item => {
return {
id: nanoid(5),
isSelected: false,
option: item
}
})
return randomAnswerList
}
function holdAnswer(id) {
setQuizData(prevQuizData => prevQuizData.map(item => {
item.answers.map(element => {
if (element.id === id) {
return {...element, isSelected: !element.isSelected}
} else {
return element
}
})
}))
}
function startQuiz() {
setQuiz(prevQuiz => !prevQuiz)
}
return (
<main>
{
quiz
?
<div className='quiz-container'>
<Quiz
quizData={quizData}
handleClick={holdAnswer}
/>
</div>
:
<Start
handleClick={startQuiz}
/>
}
</main>
)
}
Quiz.jsx
function Quiz (props) {
console.log(props.quizData)
let allAnswers = props.quizData.map(item => {
return (
<div className="question-container">
<h3 key={item.id} id={item.id} className="question-title">{item.question}</h3>
<div className="question-answers">
{item.answers.map(element => {
const styles = {
backgroundColor: element.isSelected ? "#D6DBF5" : "white"
}
return (
<button
id={element.id}
key={element.id}
style={styles}
onClick={() => props.handleClick(element.id)}
>
{element.option}
</button>
)
})}
</div>
</div>
)
})
return allAnswers
}
The formated data looks like this:
[
{
"id": "jB2iVcZ1qXqgdkvRS-dfH",
"question": "When was the programming language "C#" released?",
"correctAnswer": "2000",
"answers": [
{
"id": "_RMiu",
"isSelected": false,
"option": "1998"
},
{
"id": "MWrOT",
"isSelected": false,
"option": "1999"
},
{
"id": "psITc",
"isSelected": false,
"option": "2001"
},
{
"id": "I6Wp8",
"isSelected": false,
"option": "2000"
}
]
},
{...and so on...}
]
I've tried in several ways to change the state with the setter function, however i am stuck and i can't go further with the project.
Here is another approach that I've tried, but the results are the same: https://github.com/ktrebor/quizzical/tree/main/src
CodePudding user response:
You are not using the result of the item.answer.map()
, so the state is not updated.
function holdAnswer(id) {
setQuizData(prevQuizData => prevQuizData.map(item => ({
...item,
answers: item.answers.map(element => {
if (element.id === id) {
return {...element, isSelected: !element.isSelected}
}
return element
})
})))
}