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>
);