Ryan Nisbet
Ryan Nisbet

Reputation: 93

.map is not a function [React & Firestore]

I have been fighting this error in my code, I am creating a dropdown menu that maps the collections in my Firestore database. It is rendering the courses however, when I click on one, it gives me the following error:

enter image description here

Here is my code:

import React, { Component } from 'react'
import firebase from 'firebase/app'
import './add.css'

export default class add extends Component {

    state = {
        course: 'TestCourse1',
        question: '',
        questionType: 'MultipleChoice',
        correctAnswer: '',
        wrongAnswer: '',
        wrongAnswer2: '',
        wrongAnswer3: '',
        courses: []
    }

    componentDidMount() {
        let db = firebase.firestore()

        db.collection('courses').get().then(snapshot => {
            const courses = []
            snapshot.docs.forEach(doc => {
                const data = doc.data()
                courses.push(data)
            })
            this.setState({courses})
        }).catch(error => { console.error(error) })
    }


    handleChange = (e) => {
        this.setState({
        [e.target.id]: e.target.value,
        }) 
    }

    handleSubmit = (e) => {
        e.preventDefault();
        console.log(this.state)
    }



    render() {

        const {courses} = this.state
        return (
            <div className = "Container">
            <div className = "AddQuestion">
               <h1> Add a question </h1>
               <div className = "AddQuestionFormContainer">
                <form>

                    <label htmlFor = "courses"> Courses</label>  <br/>
                    <select name = "course" id = "courses" onChange = {this.handleChange} value = {this.state.course}>
                    {
                        courses && courses.map(course => {
                            return <option value = {course.courseName} key = {course.courseName}> {course.courseName}</option>
                        })

                    }
                    </select> <br/><br/>

                    <label  htmlFor = "question"> Question </label>  <br/>
                    <input type = "text" id = "question" placeholder = "Enter your question" onChange={this.handleChange}/>
                    <br/><br/>

                    <label  htmlFor = "question"> Question Type </label><br/>
                    <select name = "questionType" id = "questionType" onChange={this.handleChange} value = {this.state.questionType}  >
                        <option value = "MultipleChoice" > Multiple Choice</option>
                        <option value = "TrueOrFalse"> True or False </option>
                    </select>
                    <br/><br/>

                    <label  htmlFor = "correctAnswer"> Correct Answer</label> <br/>
                    <input type = "text" id = "correctAnswer" placeholder = "Correct Answer" onChange={this.handleChange}/>
                    <br/><br/>
                    <label  htmlFor = "wrongAnswer"> Wrong Answers </label><br/>
                    <input type = "text" id = "wrongAnswer" placeholder = "Wrong Answer" onChange={this.handleChange} /><br/>
                    <input type = "text" id = "wrongAnswer2" placeholder = "Wrong Answer" onChange={this.handleChange} /><br/>
                    <input type = "text" id = "wrongAnswer3" placeholder = "Wrong Answer" onChange={this.handleChange} /><br/> <br/> 

                    <button onClick = {this.handleSubmit}> Submit </button>





                </form>
               </div>
            </div>
            </div>
        )
    }
}

The value of the object is rendering to my state fine, it's just when I go to select an option in my dropdown it returns the error!

Any help would be much appreciated.

EDIT 1

After adding a console.log in my componentDidMount(), this is what is returned

CODE

 componentDidMount() {
        let db = firebase.firestore()

        db.collection('courses').get().then(snapshot => {
            const courses = []
            snapshot.docs.forEach(doc => {
                const data = doc.data()
                courses.push(data)
                console.log(courses)
            })
            this.setState({courses})
        }).catch(error => { console.error(error) })
    }

Console.log

enter image description here

Upvotes: 0

Views: 703

Answers (2)

Sarun UK
Sarun UK

Reputation: 6736

This issue is happening because, In the state you are defining courses as an array. But while handleChange overriding it into a string.

handleChange = (e) => {
       // Here overriding the value of courses to a string
        this.setState({
        [e.target.id]: e.target.value //targetId is `courses` and the value is a string
        }) 
    }

According to my understanding, you will have to track the selected course. For that change the id of select to course

<select
        name="course"
        id="course"
        onChange={this.handleChange}
        value={this.state.course}
      >

sample demo:- https://codesandbox.io/s/black-butterfly-2shjv?file=/src/App.js

Please let me know if you are facing any issues.

Upvotes: 1

Mustafa ERK
Mustafa ERK

Reputation: 66

First thing make sure your service returning an array to 'courses' and I recommend you to write like this

courses.length && courses.map(course => {
      return <option value = {course.courseName} key={course.courseName}> 
               {course.courseName}
            </option>});

Upvotes: 0

Related Questions