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:
after page refresh (expected result):
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>
)
}
CodePudding user response:
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([]);
}
});
}, []);