Skip to content
Advertisement

Problem with rendering user’s data from Firebase/Firestore using ReactJS

I’m fetching the user’s data by the user’s UID from Firestore using ReactJS into a table. First, it shows all the data from all the documents of all the users in the table, only after I refresh the page, I can see only the logged-in user data. In addition, if I change something in the code, in a specific file, the table will show again all the documents of all the users until I refresh the page again. And if I’m trying to add a value to the table, it will show all the data and the logged-in user data will be duplicated in the table. After I refresh the page again, it will show only 1 user data by UID – as I want, but only after page refresh.

I know that I have a problem with fetching data or with the useState initialization in this situation.

Screenshot before the page refresh:

enter image description here

after page refresh (expected result):

enter image description here

export default function Nutrition() {
// use state
const [data, setData] = useState([]);

useEffect(() => {
    onAuthStateChanged(auth, async (user) => {
        const dbRef = collection(db, "data");
        let foods = []
        if (user) {
            const uid = user.uid
            const snapshot = await getDoc(doc(db, "data", uid));
            if (snapshot.exists()) {
                onSnapshot(dbRef, (querySnapshot) => {
                    querySnapshot.forEach(doc => {
                        const { value, quantity } = doc.data()
                        for (let i = 0; i < value.length; i++) {
                            foods.push({ value: value[i], quantity: quantity[i] })
                        }
                    });
                    setData(foods)
                })
            } else {
                console.log("User doc missing")
            }
        } else {
            console.log("User not logged in")
            setData([])
        }
    })
}, [])

return (
    <React.Fragment>
        <div className='container mt-3'>
            {/* table */}
            <table className='table table-hover'>
                <thead>
                    <tr>
                        <th>#</th>
                        <th>Food</th>
                        <th>Quantity</th>
                    </tr>
                </thead>
                <tbody>
                    {data.map((row, index) => {
                        // console.log(data[row])
                        return (
                            <tr key={row.id}>
                                <td>{index + 1}</td>
                                <td>{row.value}</td>
                                <td>{row.quantity}</td>
                            </tr>
                        )
                    })}
                </tbody>
            </table>
            <button className='btn btn-dark mt-3'>Reset table</button>
        </div>
    </React.Fragment>
)

}

Advertisement

Answer

With the following code

            onSnapshot(dbRef, (querySnapshot) => {
                querySnapshot.forEach(doc => {
                    const { value, quantity } = doc.data()
                    for (let i = 0; i < value.length; i++) {
                        foods.push({ value: value[i], quantity: quantity[i] })
                    }
                });
                setData(foods)
            })

you actually set a real-time listener on the entire data collection since const dbRef = collection(db, "data");.

I can see only the logged-in user data

If I’m not mistaking, from your code I don’t see where you restrict the data pushed to the foods array to the data corresponding to the logged-in user. So it is not clear to me how you can “see only the logged-in user data”.

The only thing you do which is linked to a user is fetching the document of the data collection with an ID corresponding to the logged-in user ID and checking if it exists or not. And if it exists you push the entire data collection data to the foods array (so the data displaying process on your front-end is not linked to the logged-in user data, apart from checking if the user’s doc exists or not).


So if I correctly understand your goal (displaying the lines of the value and quantity arrays from the user’s document in the data collection) the following should do the trick:

  useEffect(() => {
    onAuthStateChanged(auth, async (user) => {
      let foods = [];
      if (user) {
        const uid = user.uid;
        const snapshot = await getDoc(doc(db, 'data', uid));
        if (snapshot.exists()) {
          const { value, quantity } = snapshot.data();
          for (let i = 0; i < value.length; i++) {
            foods.push({ value: value[i], quantity: quantity[i] });
          }
          setData(foods);
        } else {
          console.log('User doc missing');
        }
      } else {
        console.log('User not logged in');
        setData([]);
      }
    });
  }, []);
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement