Home > Net >  Make a new array and render it from map
Make a new array and render it from map

Time:09-22

So I've been stuck on this for a week now even though it's probably easy... I'm trying to make an array of objects using map over a hook. The final objective is to create a new hook from this new array and to be able to interact with it with some callbacks. The issue is that when I try to just render it (before creating a hook from it), I have this error showing up :

Uncaught TypeError: Cannot read properties of undefined (reading 'value')

So here is my code :

import { useState } from 'react'
import { useEffect } from 'react'
import { nanoid } from 'nanoid'
import './App.css'
import FirstPage  from './components/FirstPage'
import Quiz from './components/Quiz'

function App() {

  const [startGame, setStartGame] = useState(false)
    
    const [quizData, setQuizData] = useState([])
   


  useEffect(()=>{
      fetch(`https://opentdb.com/api.php?amount=5`)
      .then (res => res.json())
      .then (data => setQuizData(data.results))
  }, [])

  function gameStart(){
    setStartGame(true)
  }


  const displayQuestions = quizData.map(({question, correct_answer, incorrect_answers})=>{

    const answer=[]

    const answers=[]



    const questions ={
      value : question,
      id : nanoid()
    }

    const answer1={
    text : incorrect_answers.slice(0,1),
    is_selected : false,
    is_correct : false,
    id : nanoid()}

    const answer2={
    text : incorrect_answers.slice(1,2),
    is_selected : false,
    is_correct : false,
    id : nanoid()}

    const answer3={
    text : correct_answer,
    is_selected : false,
    is_correct : true,
    id : nanoid()}

    const answer4={
    text : incorrect_answers.slice(2),
    is_selected : false,
    is_correct : false,
    id : nanoid()}

    const answersOptions = answers.push(answer1,answer2,answer3,answer4)

    const quiz = answer.push(questions, answers)

              
                return <div>
                {
                  answer.map(({questions, answers}) => (
                  <ul key={questions.id} > 
                  <li className='questions'>{questions.value}</li>
                    <button className='answers'>{answers.text}</button>
                    </ul>
                  ))
                }
                </div>
    
})

  return (
    <>
    <h1 className='bloc'></h1>
    <h1 className='bloc2'></h1>
      {startGame 
      ?  
      <Quiz displayQuestions={displayQuestions}/>
      :
      <FirstPage gameStart={gameStart}/>
      }
    </>
    
  );
}

export default App

The main project is to make a quiz using some datas from an API. Thank you for your help !

CodePudding user response:

First of all, you can't just throw everything in the answer array and destruct it that way. Since you're getting the elements one by one from the quizData array anyway, you're only interested in a single question here, not questions. You must write the question on one line in the jsx you return and return the answers in the loop, otherwise you will have rewritten the same question for each answer.

const displayQuestions = quizData.map(
  ({ question, correct_answer, incorrect_answers }) => {
    const answers = [
      {
        text: correct_answer,
        is_selected: false,
        is_correct: true,
        id: nanoid()
      },
      ...incorrect_answers.map((inc) => ({
        text: inc,
        is_selected: false,
        is_correct: false,
        id: nanoid()
      }))
    ];
    const q = {
      value: question,
      id: nanoid()
    };
    // to shuffle
    let shuffledAnswers = answers
      .map((value) => ({ value, sort: Math.random() }))
      .sort((a, b) => a.sort - b.sort)
      .map(({ value }) => value);
    return (
      <div>
        <div key={q.id}>{q.value}</div> {/* question part */}
        {shuffledAnswers.map(({ id, text, is_selected, is_correct }) => (
          <ul key={id}>
            <li className="answers">
              {text}
            </li>
          </ul>
        ))}
      </div>
    );
  }
);

CodePudding user response:

The issue is that you are trying to push the questions and answers variables as items to the answer array, but in fact you need to create an object with the questions and answers properties and push to the array after.

Doing the way you did, the array would be equal to [questions, answers], but in fact you want it to be [{questions, answers}], then you could destruct the item and get the questions and answers properties.

So, in the line:

      const quiz = answer.push(questions, answers);

It should be:

      const quiz = answer.push({questions, answers});

But, the answer array is not necessary in this situation, since it's going to have just 1 item anyway.

  • Related