1

I am writing a Reactjs website and fetching data from a firebase database. I store the fetched data into a react state. However when i try to use map function for the state. It didn't work and no error message is shown.

my code is like this

import React from 'react';
import { data } from './data.js'
import { useState, useEffect } from 'react';

export default function Navi(props) {

    const [state,setState] = useState([])

    useEffect(() => {
        const fetchData = () =>{
            var info = []
            props.db.collection("data").get().then((querySnapshot) => {
                querySnapshot.forEach((doc) => {
                    info.push({id:doc.id, name:doc.data().name})
                });
            });
            setState(info)
        }
        fetchData()
      },[]);



    return (
        <div>
            <Navbar bg="light" expand="lg">
                <Navbar.Brand href="/home">Logo</Navbar.Brand>
                <Navbar.Toggle aria-controls="basic-navbar-nav" />
                <Navbar.Collapse id="basic-navbar-nav">
                    <Nav className="mr-auto">
                        <Nav.Link href="/report">re</Nav.Link>
                        <Nav.Link href="/call">call</Nav.Link>
                        <Nav.Link href="/suck">suck</Nav.Link>
                        <NavDropdown title="r" id="basic-nav-dropdown">
                            {   
                                console.log(1)||
                                state.map(x=>{
                                    console.log(x)
                                })&&
                                console.log(2)
                            }   

                        </NavDropdown>
                    </Nav>
                </Navbar.Collapse>
            </Navbar>
        </div>
    )
}

The console.log(1) and console.log(2) are for debug purpose. Both console.log() can be shown no problem. But the map function is not working.

I have tried to only write the console.log(state), it can log a []empty array in the first render and after the component mounted, it can log the value in the state.

miketsui3a
  • 181
  • 1
  • 4
  • 14
  • [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Andreas Oct 07 '19 at 10:43

2 Answers2

0

The problem is here:

var info = []
props.db.collection("data").get().then((querySnapshot) => {
  querySnapshot.forEach((doc) => {
    info.push({id:doc.id, name:doc.data().name})
  });
});

setState(info) <-- HERE

You're setting the state outside of the promise then function so in the first cycle the state is populated with setState([]) and when the async response from DB arrives then the object info is updated (you should never update an object in state, it should be always immutable) but React isn't notified about the state change so there is no next rerender.

How to fix it? Put the setState(info) call inside the promise resolve (then) function.

Jan Steuer
  • 141
  • 4
0

Problem is here

useEffect(() => {
    const fetchData = () =>{
        var info = [] // <-- EMPTY
        props.db.collection("data").get().then((querySnapshot) => {
            querySnapshot.forEach((doc) => {
                info.push({id:doc.id, name:doc.data().name})
            });
        });
        setState(info)  // <-- still EMPTY
    }
    fetchData()
  },[]);

You do not properly understand Promises, read them now

useEffect(() => {
    const fetchData = () =>{
        props.db.collection("data").get()
            .then((querySnapshot) => {
                const info = querySnapshot.map((doc) => ({id:doc.id, name:doc.data().name}))
                setState(info)
            })
    }
    fetchData()
  },[]);
Medet Tleukabiluly
  • 11,662
  • 3
  • 34
  • 69