skip to Main Content

A screenshot of the error message can be viewed here.

Hello folks,

I was trying to build a quiz app using the MERN stack.
Though everything is working, cannot access the list of questions as it throws the TypeError: Cannot read properties of undefined (reading ‘map’).

I am currently using the map() function in two component JavaScript files: Questions.js, and ResultTable.js.

If you can please guide me, that would be of great help.

Thanks in advance! 🙂

QUESTIONS.JS

import React, { useEffect, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'


/** Custom Hook */
import { useFetchQestion } from '../hooks/FetchQuestion'
import { updateResult } from '../hooks/setResult'


export default function Questions({ onChecked }) {

    const [checked, setChecked] = useState(undefined)
    const { trace } = useSelector(state => state.questions);
    const result = useSelector(state => state.result.result);
    const [{ isLoading, apiData, serverError}] = useFetchQestion() 

    const questions = useSelector(state => state.questions.queue[state.questions.trace])
    const dispatch = useDispatch()

    useEffect(() => {
        dispatch(updateResult({ trace, checked}))
    }, [checked])
    
    function onSelect(i){
        onChecked(i)
        setChecked(i)
        dispatch(updateResult({ trace, checked}))
    }


    if(isLoading) return <h3 className='text-light'>isLoading</h3>
    if(serverError) return <h3 className='text-light'>{serverError || "Unknown Error"}</h3>

  return (
    <div className='questions'>
        <h2 className='text-light'>{questions?.question}</h2>

        <ul key={questions?.id}>
            {
                questions?.options.map((q, i) => (
                    <li key={i}>
                        <input 
                            type="radio"
                            value={false}
                            name="options"
                            id={`q${i}-option`}
                            onChange={() => onSelect(i)}
                        />

                        <label className='text-primary' htmlFor={`q${i}-option`}>{q}</label>
                        <div className={`check ${result[trace] == i ? 'checked' : ''}`}></div>
                    </li>
                ))
            }
        </ul>
    </div>
  )
}

RESULT_TABLE.JS

import React, { useEffect, useState } from 'react'
import { getServerData } from '../helper/helper'

export default function ResultTable() {

    const [data, setData] = useState([])

    useEffect(() => {
        getServerData(`${process.env.REACT_APP_SERVER_HOSTNAME}/api/result`, (res) => {
            setData(res)
        })
    })

  return (
    <div>
        <table>
            <thead className='table-header'>
                <tr className='table-row'>
                    <td>Name</td>
                    <td>Attemps</td>
                    <td>Earn Points</td>
                    <td>Result</td>
                </tr>
            </thead>
            <tbody>
                { !data ?? <div>No Data Found </div>}
                {
                    data.map((v, i) => (
                        <tr className='table-body' key={i}>
                            <td>{v?.username || ''}</td>
                            <td>{v?.attempts || 0}</td>
                            <td>{v?.points || 0}</td>
                            <td>{v?.achived || ""}</td>
                        </tr>
                    ))
                }
                
            </tbody>
        </table>
    </div>
  )
}

2

Answers


  1. The error "TypeError: Cannot read properties of undefined (reading ‘map’)" occurs when the map() function is called on an object that is undefined or null. In your case, the error is coming from the Questions.js and ResultTable.js files when trying to access the ‘map’ method on the options and data objects respectively.

    In the Questions.js file, the questions object is defined as state.questions.queue[state.questions.trace], which might be undefined if the state is not set properly. Therefore, you should add a null check before accessing the options object as shown below:

    {
        questions?.options && questions?.options.map((q, i) => (
            <li key={i}>
                <input 
                    type="radio"
                    value={false}
                    name="options"
                    id={`q${i}-option`}
                    onChange={() => onSelect(i)}
                />
    
                <label className='text-primary' htmlFor={`q${i}-option`}>{q}</label>
                <div className={`check ${result[trace] == i ? 'checked' : ''}`}></div>
            </li>
        ))
    }
    

    Similarly, in the ResultTable.js file, you should also check if the data object is defined before accessing its map() method. You can modify the code as shown below:

    {data && data.map((v, i) => (
        <tr className='table-body' key={i}>
            <td>{v?.username || ''}</td>
            <td>{v?.attempts || 0}</td>
            <td>{v?.points || 0}</td>
            <td>{v?.achived || ""}</td>
        </tr>
    ))}
    

    By adding these null checks, you can avoid the TypeError: Cannot read properties of undefined (reading ‘map’) error in your code.

    Login or Signup to reply.
  2. In Question.js please change the return to the following.

        return (
        {  (!isLoading) && (
    
        <div className='questions'>
            <h2 className='text-light'>{questions?.question}</h2>
    
            <ul key={questions?.id}>
                {
                    questions?.options?.map((q, i) => (
                        <li key={i}>
                            <input 
                                type="radio"
                                value={false}
                                name="options"
                                id={`q${i}-option`}
                                onChange={() => onSelect(i)}
                            />
    
                            <label className='text-primary' htmlFor={`q${i}-option`}>{q}</label>
                            <div className={`check ${result[trace] == i ? 'checked' : ''}`}></div>
                        </li>
                    ))
                }
            </ul>
        </div>
    
      ))
    

    I have added (!isLoading) and questions?.options?.map in the code. If this still throws error console.log(questions?.options) and see the question list in the browser. if that is undefined you have recheck your custom hook useFetchQestion().

    One other possibility could be you are destructuring the useQuestion hook the wrong. if you are just getting a object do it as

    const { isLoading, apiData, serverError} = useFetchQestion()
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search