I am building a chat application on React Native with Firestore backend.
My structure is like this:
Channels
-Channel
{
user1,
user2,
messages:[] (This is a subcollection not an array inside the document)
}
I want to check if there is a channel contains the selected users.
Checker function:
const [chatRef, setChatRef] = useState()
let channelRef = db.collection("Channels")
channelRef.get().then((snapshot) => {
snapshot.forEach((doc) => {
let room = doc.data()
if (
(room.user1.id === user.id || room.user2.id === user.id) &&
(room.user1.id === personToChat.id || room.user2.id === personToChat.id)
) {
setChatRef(channelRef.doc(room.id).collection("Messages"))
} else {
channelRef.doc(user.id).set({
user1: user,
user2: personToChat,
})
setChatRef(channelRef.doc(user.id).collection("Messages"))
}
})
})
useEffect:
useEffect(() => {
const unsubscribe = chatRef.onSnapshot((querySnapshot) => {
const messagesFirestore = querySnapshot
.docChanges()
.filter(({ type }) => type === "added")
.map(({ doc }) => {
const message = doc.data()
return { ...message, createdAt: message.createdAt.toDate() }
})
.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime())
appendMessages(messagesFirestore)
})
return () => unsubscribe()
}, [])
What I tried?
- I tried to use a variable instead of a state. Didn't work.
- I tried to get the chatRef variable with a function. Didn't work.
- I used chatRef as a dependency. Didn't work.
- I called the check function inside the useEffect. Didn't work.
All this leads to same error which is,
TypeError: undefined is not an object (evaluating 'chatRef.onSnapshot')
CodePudding user response:
It occours because your chatRef state isn't initialized when your useEffect is running. Your useEffect only runs once because of the empty array of dependencies.
CodePudding user response:
I solved it by sending chatRef as a prop from the parent component. And used it as a dependency in child component.
This function is from the contact list page. It handles the press event on contacts. When clicked it navigates to chatroom. I used React.useRef for storing the chatRef and sending it as a prop to the chatroom.
if (
(room.user1.id === user.id || room.user2.id === user.id) &&
(room.user1.id === contact.id || room.user2.id === contact.id)
) {
chatRef.current = channelRef.doc(room.id).collection("Messages")
navigation.navigate("ChatRoom", {
personToChat: contact,
chatRef: chatRef.current,
})
}
Then in chatroom screen I used it as a dependency and checked if its null.
useEffect(() => {
if (chatRef) {
const unsubscribe = chatRef.onSnapshot((querySnapshot) => {
const messagesFirestore = querySnapshot
.docChanges()
.filter(({ type }) => type === "added")
.map(({ doc }) => {
const message = doc.data()
return { ...message, createdAt: message.createdAt.toDate() }
})
.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime())
appendMessages(messagesFirestore)
})
return () => unsubscribe()
}
}, [chatRef])