Home > Net >  react firebase firestore empty useEffect useState
react firebase firestore empty useEffect useState

Time:07-16

having an issue, when the when nav to the comp the items state is empty, if I edit the code and page refreshes its shows up and if I add the state to the useEffect "[itemCollectionRef, items]" it's an inf loop but the data is their anyone have a better idea or way to fetch the data for display from firestore.

import React, { useState, useEffect } from "react";
import { Grid, Box, Button, Space } from "@mantine/core";
import { ItemBadge } from "../../components/NFAItemBadge";
import { useNavigate } from "react-router-dom";
import { db, auth } from "../../firebase";
import { getFirestore, query, getDocs, collection, where, addDoc } from "firebase/firestore";
import { useAuthState } from "react-firebase-hooks/auth";


const ItemTrack = () => {
  const [user, loading, error] = useAuthState(auth);
  const navigate = useNavigate();

  const [items, setItems] = useState([]);
  const itemCollectionRef = collection(db, "items");

  useEffect(() => {
    //if(!user) return navigate('/');
    //if(loading) return;
    const q = query(itemCollectionRef, where("uid", "==", user.uid));
    const getItems = async () => {
      const data = await getDocs(q);
      setItems(data.docs.map((doc) => ({ ...doc.data(), id: doc.id })));
      console.log("Fetched Items: ", items);
    };
    getItems();
  }, []);

  if (loading) {
    return (
      <div>
        <p>Initialising User....</p>
      </div>
    );
  }
  if (error) {
    return (
      <div>
        <p>Error: {error}</p>
      </div>
    );
  }
  if (user) {
    return (
      <Box sx={{ maxWidth: 1000 }} mx="auto">
      </Box>
    );
  } else {
    return navigate("/");
  }
};

export default ItemTrack;

CodePudding user response:

It will depend how you will render the data from the useEffect. setState does not make changes directly to the state object. It just creates queues for React core to update the state object of a React component. If you add the state to the useEffect, it compares the two objects, and since they have a different reference, it once again fetches the items and sets the new items object to the state. The state updates then triggers a re-render in the component. And on, and on, and on...

As I stated above, it will depend on how you want to show your data. If you just want to log your data into your console then you must use a temporary variable rather than using setState:

useEffect(() => {
  const newItems = data.docs.map((doc) => ({ ...doc.data(), id: doc.id }))
  console.log(newItems)
  // setMovies(newItems)
}, [])

You could also use multiple useEffect to get the updated state object:

useEffect(() => {
  setItems(data.docs.map((doc) => ({ ...doc.data(), id: doc.id }))) 
}, [])
useEffect(() => { console.log(items) }, [items])

If you now want to render it to the component then you have to call the state in the component and map the data into it. Take a look at the sample code below:

useEffect(() => {
  const q = query(itemCollectionRef, where("uid", "==", user.uid));
  const getItems = async () => {
    const data = await getDocs(q);
    setItems(data.docs.map((doc) => ({ ...doc.data(), id: doc.id })));
  };
  getItems();
}, []);

return (
  <div>
    <p>SomeData: <p/>
    {items.map((item) => (
      <p key={item.id}>{item.fieldname}</p>
    ))}
  </div>
);
  • Related