I'm fetching some data from firestore and everything works, but there is one big flaw I'm trying to figure out…
I can only console log the data once I press on the “Read Data” button twice. Any help on how I can make it wait for it to have the response before showing it?
Bellow is my code, thanks in advance.
import firebase from 'firebase/compat/app'
import 'firebase/compat/firestore';
import { useState } from 'react';
export default function ReadToFirebase() {
const [data, setData] = useState([])
const readData = () => {
try {
firebase
.firestore()
.collection('users')
.onSnapshot(snapshot => {
let changes = snapshot.docChanges()
changes.forEach(change => {
let data = change.doc.data()
data = {
username: data.userName,
email: data.email
}
setData(oldArray => [...oldArray, data])
})
})
console.log('Data Read!')
console.log(data);
// return data
} catch (error) {
console.log(`Opps! Error querying data: \n\n ${error}`);
alert(error)
}
}
return (
<div className="p-4 grid place-items-center space-y-2">
<button onClick={readData} className="py-2 px-4 bg-gray-300 rounded-xl font-bold">Read Data</button>
<div className="">{}</div>
</div>
)
}
Your console.log statement is outside the onSnapshot function.
If you do something like this:
const readData = () => {
try {
firebase
.firestore()
.collection('users')
.onSnapshot(snapshot => {
let changes = snapshot.docChanges()
changes.forEach(change => {
let data = change.doc.data()
data = {
username: data.userName,
email: data.email
}
setData(oldArray => [...oldArray, data])
});
console.log('Data Read!')
console.log(data);
})
// return data
} catch (error) {
console.log(`Opps! Error querying data: \n\n ${error}`);
alert(error)
}
}
It'll work.
Two things to note here:
map instead of forEach:const changedData = changes.map(change => {
let data = change.doc.data()
return {
username: data.userName,
email: data.email
}
});
setData(oldArray => [...oldArray, ...changedData])
try/catch to actually catch server error you should wrap your request in a promise. Something like:const readData = () => {
new Promise((resolve, reject) => {
firebase.firestore().collection('users').onSnapshot(handleSnapshot(resolve, reject)());
})
.then(handleSuccessfulUsersFetch)
.catch(handleErrorInUsersFetch);
}
There are other ways you could achieve that (for instance with async/await). You can read more about error handling in JS in this nice article: https://medium.com/walkme-engineering/javascript-error-handling-9fc1a2946119