Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Is there a way to change an object's property from an array which is part of another object, nested in an array in React using only two components?

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

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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 &quot;C#&quot; 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

>Solution :

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
      })
   })))
  }
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading