Home > Net >  Calculated variable returns undefined in useEffect
Calculated variable returns undefined in useEffect

Time:09-24

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])
  • Related