Home > Back-end >  React, update state with .map() and spread operator in nested array of objects
React, update state with .map() and spread operator in nested array of objects

Time:12-03

I'm still a newbie in React and I've been struggling for some time with the topic mentioned above. I've got a state which looks like this:

const [questions, setQuestions] = React.useState([])    
    React.useEffect(()=>{
        fetch('https://the-trivia-api.com/api/questions?limit=5&difficulty=medium').then((response)=>response.json()).then((data)=>{
            let questionsData = data.map((item) => {
                return {
                    id: nanoid(),
                    questionText: item.question,
                    answerOptions: [
                        {id: nanoid(), answerText: item.correctAnswer, isCorrect: true, selected: false,},
                        {id: nanoid(), answerText: item.incorrectAnswers[0], isCorrect: false, selected: false,},
                        {id: nanoid(), answerText: item.incorrectAnswers[1], isCorrect: false, selected: false,},
                        {id: nanoid(), answerText: item.incorrectAnswers[2], isCorrect: false, selected: false,},
                    ].sort(()=>Math.random() -0.5),
                };
            })
            setQuestions(questionsData)
            })
        
    }, [])

It's a state that returns me a quiz question and 4 "randomized" buttons. What I'm trying to do is to update the state to make one of the answerOptions (that is buttons) from selected: false to selected: true. I'm sure it's doable with .map and spread operator but I'm really lost with the syntax

selectAnswer is triggered by an onChange from the radio buttons from the child Component. I have access to both the question id and each of the answerOptions id so accessing those is not a problem. I just can't figure out how to return the state. Below is an example of my failed attempt to do that.

    function selectAnswer(answerId, questionId){
        setQuestions(prevData => prevData.map((item)=>{
            return item.answerOptions.map((answerItem)=>{
                if(answerId === answerItem.id) {
                    return {...item, [answerOptions[answerItem].selected]: !answerOptions[answerItem].selected}
                } else return {...item}
            })
        }))
        }

Thank you for your time in advance

CodePudding user response:

In order to update the state of your component to set the selected property of one of the answerOptions to true, you can use the map method to iterate over the existing questions in the state, find the answerOption with the matching id, and update its selected property. You can use the spread operator (...) to create a new object for each question that includes the updated answerOption.

Here is an example of how you could implement this in your selectAnswer function:

function selectAnswer(answerId, questionId) {
  setQuestions(prevData =>
    prevData.map(question => {
      // Create a new array of answerOptions for this question,
      // with the selected answerOption updated to have its selected property set to true.
      const answerOptions = question.answerOptions.map(answerOption => {
        if (answerOption.id === answerId) {
          return { ...answerOption, selected: true };
        } else {
          return answerOption;
        }
      });

      // Return a new object for this question with the updated answerOptions array.
      return { ...question, answerOptions };
    })
  );
}

In this example, the selectAnswer function uses the map method to iterate over the existing questions in the state. For each question, it creates a new array of answerOptions, with the answerOption that has the matching id updated to have its selected property set to true. It then returns a new object for the question with the updated answerOptions array.

CodePudding user response:

function selectAnswer(answerId, questionId) {
  setQuestions((prevData) =>
    prevData.map((item) => ({
      ...item,
      answerOptions: item.answerOptions.map((answerItem) => ({
        ...answerItem,
        selected: answerId === answerItem.id,
      })),
    }))
  );
}
  • Related