Home > OS >  Fetched firestore data not displaying on first page load with React useEffect()
Fetched firestore data not displaying on first page load with React useEffect()

Time:07-13

I am trying to display data from a firestore database by pushing it to an array and mapping it. My goal is to have it display on the first page load, however, it only displays after I make changes to my code and I don't know why. My suspicion is that it has something to do with the dataArray.push() not waiting for the fetch to finish, but I'm not sure. I'll attach some images to show what I mean, I have tried fixing this but nothing works.

On first page load: https://i.stack.imgur.com/RM6sU.png

After editing the code: https://i.stack.imgur.com/u43We.png

import '../css/ClassBox.css'

import { db } from '../Firebase/firebase'
import { doc, getDoc } from 'firebase/firestore';

function ClassBox() {

  const [dataArray, setDataArray] = useState([])
  const [classesArray, setClassesArray] = useState([])

  useEffect(() => {
    const fetchUserData = async () => {
        var tempArray = []
        const userData = await getDoc(doc(db, 'users', localStorage.getItem('id')))
        tempArray.push(userData.data().classes)
        tempArray = tempArray.toString().replace(/\s*\,\s*/g, ",").trim().split(",")
        setClassesArray(tempArray)
    }
    const fetchClassData = async () => {
        for(let i=0; i<classesArray.length; i  ) {
            let data = await getDoc(doc(db, 'classes', classesArray[i]))
            dataArray.push(data.data())
        }
        console.log(dataArray)
    }
    fetchUserData()
    .then(fetchClassData())
  }, [])

  return (
    <div className='classBoxList'>
        {dataArray.map((classes) => (
            <div className='classBox'>
                <div className='classBoxContainer'>
                    <div kclassName='classBoxWrapper'>
                        <div className='statusContainer'>
                            <h3>CS 106</h3>
                            <h4 key={classes.status}>{classes.status}</h4>
                        </div>
                        <div className='classInfoContainer'>
                            <ul>
                                <li key={classes.classCRN}>CS 106 - {classes.classCRN}</li>
                                <li key={classes.instructorName}>{classes.instructorName}</li>
                                <li key={classes.building}>{classes.building}</li>
                                <li key={classes.instructionMethod}>{classes.instructionMethod}</li>
                                <li key={classes.takenSeats}>Seats: {classes.takenSeats}/{classes.totalSeats}</li>
                                <li key={classes.remainingSeats}>Remaining: {classes.remainingSeats}</li>
                            </ul>
                        </div>
                    </div>
                </div>
            </div>
        ))}
    </div>
  )
}

export default ClassBox ```

CodePudding user response:

You are incorrectly mutating the dataArray state variable using push. You should use setDataArray() instead.

CodePudding user response:

First, inside .then (next to fetchUserData), you wrote a function call rather than a callback. Change it to .then(() => callback()) or .then(callback).

Second, state changes inside useEffect loop reflects changes only after the next render. So even after calling setClassesArray inside fetchUserData, fetchClassData will be called with the previous value of classesArray.

Third, you can't push to dataArray directly, rather use setDataArray call only.

Try this:

  useEffect(() => {
    const fetchUserData = async () => {
        let tempArray = []
        const userData = await getDoc(doc(db, 'users', localStorage.getItem('id')))
        tempArray.push(userData.data().classes)
        tempArray = tempArray.toString().replace(/\s*\,\s*/g, ",").trim().split(",")
        setClassesArray(tempArray)
        return tempArray
    }
    const fetchClassData = async (newClassesArray) => {
        let tempArray = []
        for(let i=0; i<newClassesArray.length; i  ) {
            let data = await getDoc(doc(db, 'classes', classesArray[i]))
            tempArray.push(data.data())
        }
        setDataArray(tempArray)
    }
    fetchUserData()
    .then((tempArray) => fetchClassData(tempArray))
  }, [])
  • Related