The following is a component that maps through the objects in a context variable and renders them.
const MyGroups = () => {
const { myGroups } = useContext(GlobalContext);
return (
<div className="my__groups">
<h1 className="my__groups__heading">My Groups</h1>
<div className="my__groups__underline"></div>
<div className="my__groups__grid__container">
{
myGroups.map(({id, data}) => (
<GroupCard
key={id}
name={data.name}
image={data.image}
/>
))
}
</div>
</div>
)
}
The following is my store function which I use to fetch my data from Firebase and dispatch an action to the Reducer.
function fetchGroupsFromDatabase(id) {
let myGroups = [];
db.collection("users").doc(id).get() // Fetch user details with given id
.then(doc => {
doc.data().groupIDs.map(groupID => { // Fetch all group IDs of the user
db.collection("groups").doc(groupID).get() // Fetch all the groups
.then(doc => {
myGroups.push({id: doc.id, data: doc.data()})
})
})
})
.then(() => {
const action = {
type: FETCH_GROUPS_FROM_DATABASE,
payload: myGroups
};
dispatch(action);
})
}
Now, the problem is that the "GroupCards" that I want to render, are not rendering although I can see in the console that the context variable get's populated after some time.
Working perfectly with setTimeout()
However, I have observed that instead of dispatching the action within the THEN construct, if I dispatch my action after some seconds by setTimeout, my component renders perfectly, like this:
function fetchGroupsFromDatabase(id) {
let myGroups = [];
db.collection("users").doc(id).get() // Fetch user details with given id
.then(doc => {
doc.data().groupIDs.map(groupID => { // Fetch all group IDs of the user
db.collection("groups").doc(groupID).get() // Fetch all the groups
.then(doc => {
myGroups.push({id: doc.id, data: doc.data()})
})
})
})
setTimeout(() => {
const action = {
type: FETCH_GROUPS_FROM_DATABASE,
payload: myGroups
};
dispatch(action);
}, 3000);
}
I humbly request you to kindly spare some of your valuable time and provide some solution to my problem.
Thank You very much.
In order to wait for all of the groups .get()
calls to resolve, and to dispatch with the results, use Promise.all
:
async function fetchGroupsFromDatabase(id) {
const doc = await db.collection("users").doc(id).get() // Fetch user details with given id
const myGroups = await Promise.all(
doc.data().groupIDs.map(groupID => // Fetch all group IDs of the user
db.collection("groups").doc(groupID).get() // Fetch all the groups
.then(doc => ({ id: doc.id, data: doc.data() }))
)
);
const action = {
type: FETCH_GROUPS_FROM_DATABASE,
payload: myGroups
};
dispatch(action);
}