I am trying to add some properties to an array of objects inside useEffect but it renders DOM while those fields are still not present. Is there any reliable way how to wait till those properties are added:
useEffect hook look like this:
useEffect(() => {
onSnapshot(query(collection(db, "conversations"), where('canRead', 'array-contains', user.user.uid), orderBy("lastMsgDate", 'desc')),
async (snapshot) => {
let conversations = snapshot.docs.map(doc => toConversation(doc, user.user.uid));
await conversations.map(async (convo, index) => {
const profile = await getDoc(doc(db, "users", convo.canRead[0]))
conversations[index].picture = profile.data().picture
conversations[index].name = profile.data().name
})
setConversations(conversations)
})
}, []);
This is how I am rendering list of convos:
<IonCard>
{conversations.length > 0 ?
conversations.map((conversation) =>
<IonItem key={conversation.id}>
<IonAvatar slot='start'>
<img src={conversation.picture ? conversation.picture : '/assets/default-profile.svg'} alt={conversation.name} />
</IonAvatar>
<IonLabel>{conversation.name}</IonLabel>
</IonItem>
)
:
<IonCardContent>
no convos
</IonCardContent>
}
</IonCard>
the name and picture does not render even i can see it when log array into console
0:{
canRead: ['iwPmOBesFQV1opgs3HT9rYPF7Sj1'],
id: "W6cefXGoBAZijPof8jVl",
lastMsg: "test",
lastMsgDate: nt {seconds: 1668418292, nanoseconds: 281000000},
lastMsgSender: "Hyw4Argt8rR25mFaFo1Sl4iAWoM2",
name: "Warren"
picture: "https://firebasestorage.googleapis.com/v0/b/..."
users: {
Hyw4Argt8rR25mFaFo1Sl4iAWoM2: true,
iwPmOBesFQV1opgs3HT9rYPF7Sj1: true
}
}
Any help appreciated
CodePudding user response:
You can use a loading message or a gif.
const [loading, setLoading] = useState(true);
useEffect(() => {
onSnapshot(query(collection(db, "conversations"), where('canRead', 'array-contains', user.user.uid), orderBy("lastMsgDate", 'desc')),
async (snapshot) => {
....
setConversations(conversations);
setLoading(false);
})
}, []);
if(loading) return <p>Loading...</p>
return <> your content </>
CodePudding user response:
for some reason it works with setTimeout
function which is not the best solution
useEffect(() => {
setLoading({ loading: true, loadingMsg: 'Loading conversations' })
onSnapshot(query(collection(db, "conversations"), where('canRead', 'array-contains', user.user.uid), orderBy("lastMsgDate", 'desc')),
async (snapshot) => {
let convos = snapshot.docs.map(doc => toConversation(doc, user.user.uid));
await convos.map(async (convo, index) => {
const profile = await getDoc(doc(db, "users", convo.canRead[0]))
convos[index].picture = profile.data().picture
convos[index].name = profile.data().name
})
setTimeout(() => {
setConversations(convos)
setLoading({ loading: false, loadingMsg: undefined })
}, 1000);
})
}, [user.user.uid]);
CodePudding user response:
Maybe u can add a loading state? something like
const [loading, setLoading] = useState(false);
const [conversations,setConversations] = useState(null);
const onSnapshot = async () => {
setLoading(true)
onSnapshot(
query(
collection(db, "conversations"),
where("canRead", "array-contains", user.user.uid),
orderBy("lastMsgDate", "desc")
),
async (snapshot) => {
let conversations = snapshot.docs.map((doc) =>
toConversation(doc, user.user.uid)
);
await conversations.map(async (convo, index) => {
const profile = await getDoc(doc(db, "users", convo.canRead[0]));
conversations[index].picture = profile.data().picture;
conversations[index].name = profile.data().name;
});
setConversations(conversations);
}
);
setLoading(false);
};
useEffect(() => {
onSnapshot()
},[])
return loading ? <span>loading...</span> : <div>{conversations.map((con,i) => <span key={i}>con</span>)}</div>