I'm using Firebase v9, I'm building a chat app, I need to do some async work before calling onSnapShot to get the chat data :
const getChat = async () => {
// I need to await for user data before doing anything else.
// I'll need some user data to build the query which
// I'll be using in onSnapShot later on.
const user = await getUserData();
console.log(user);
const collectionRef = collection(db, "messages");
const q = query(
collectionRef, where("user_id", "==", user.id), orderBy("createdAt"));
const unsubscribe = onSnapshot(q, (snapshot) => {
const data = snapshot.docs.map((doc) => {
const entry = doc.data();
return {
id: doc.id,
message: entry.message,
};
});
setChatLines(data);
});
return unsubscribe;
};
Then in useEffect :
useEffect(() => {
const unsubscribe = getChat();
return () => {
unsubscribe();
};
}, []);
The problem here is that unsubsribe
is a promise, because getChat
is async, but I still want to await getUserData()
before onSnapShot is called, because I'll be needing the user data in the onSnapShot query later.
Is there a way to make this work while being able to unsubscribe
correctly in useEffect cleanup function ?
CodePudding user response:
In this case I would suggest using a React ref to hold the unsubscribe function to be used in an useEffect
cleanup function.
const unsubscribeRef = React.useRef();
const getChat = async () => {
const user = await getUserData();
const collectionRef = collection(db, "messages");
const q = query(
collectionRef, where("user_id", "==", user.id), orderBy("createdAt"));
const unsubscribe = onSnapshot(q, (snapshot) => {
const data = snapshot.docs.map((doc) => {
const entry = doc.data();
return {
id: doc.id,
message: entry.message,
};
});
setChatLines(data);
});
unsubscribeRef.current = unsubscribe;
};
useEffect(() => {
getChat();
return () => {
unsubscribeRef.current?.();
};
}, []);
An alternative would be an additional asynchronous function in the useEffect
hook callback body that can wait for getChat
Promise to resolve.
useEffect(() => {
let unsubscribe;
const getChatAndSubscribe = async () => {
unsubscribe = await getChat();
}
getChatAndSubscribe();
return () => {
unsubscribe?.();
};
}, []);