Problem:
I’m trying to populate a React component using data available in Firestore.
I can get a console.log of the data without any problems, however, the dynamic element population doesn’t happen, either by calling the Promise directly or through useEffect.
The only time I have it worked is when I add an onclick event on the element and taking it away after the first click.
const OptionList = () => {
const [list, setList] = useState({})
const fetchData = () => {
let data = [];
const response = getDocs(collection(db, 'listing'));
response.then((results) => {
let id = 1;
results.forEach(function(doc) {
const tempData = {id:id, name: doc.id, active: doc.data().active}
id+=1;
data.push(tempData);
});
})
setList(data)
}
// useEffect(() => {
// fetchData()
// }, []);
return(
<>
<select name="collection" id="collection" className="w-full rounded-lg border-2 border-gray-200 p-3 placeholder-zinc-500" >
<option value="new">New Collection</option>
{Object.values(list).map((item) => <option key={item.id} value={item.name}>{item.name}</option> )}
{Object.values(list).forEach((item) => console.log(item) )}
</select>
</>
)
}
Any indication of where to issues lie is very much appreciated.
Solution:
Put the call to setList inside the promise callback. Right now it’s always setting an empty list before the database results are hanlded, because promise callbacks are always asynchronous.
response.then((results) => {
let id = 1;
results.forEach(function(doc) {
const tempData = {id:id, name: doc.id, active: doc.data().active}
id+=1;
data.push(tempData);
});
setList(data)
})
If you add more logging in and around the callback you’ll be able to better see the order in which everything executes.