Joseph
Joseph

Reputation: 604

react useEffect strange behaviour - can't explain?

I have the following code in a useEffect

    useEffect(() => {
    async function fetchMessages() {
      let messages = [];

      const firestore = firebase.firestore();
      const query = firestore.collection('chats').where("repliedTo", "==", false).where("type", "==", "StudentQuery").orderBy("timestamp", "desc"); 
  
      query.onSnapshot({
        next: (querySnapshot) => {
          querySnapshot.forEach((doc) => {
            console.log("x ", doc.id, '=>', doc.data());
            messages.push({mid: doc.id, ...doc.data()});
            console.log(messages)
          });
        },
      });
      setMessagesList(messages)
      setMessageCount(messagesList.length)
      console.log('xxxx' + messagesList.length)    
    }
    fetchMessages();
  }, [messagesList.length]);

A few things seem to be wrong with this and I can't see it.

  1. When I trigger this code (by inserting a new record into Firestore) what I expect would be to see a console.log with the (final) array size (so previous array size + 1) - but instead what I am seeing is the previous array + (previous array + 1 entry) I would have thought he let messages = [] would have cleared the array every time an update happened?

  2. I never see the console.log("xxx") in my console. I want to put a state update here as this line should be safe as the database read has done, but since the line doesn't appear I don't know what's going wrong.

Can anyone shed some insight?

Upvotes: 0

Views: 46

Answers (1)

gerrod
gerrod

Reputation: 6627

I've not used firebase before but it looks like you're effectively creating a subscription which is getting called outside of React's render cycle.

You could just add a state property that you update when next is called, eg:

const [messages, setMessages] = useState([]);

// Use the `useEffect` to set up / tear down the subscription
useEffect(() => {
    const firestore = firebase.firestore();
    const query = firestore.collection(...);

    const unsubscribe = query.onSnapshot({
        next: (querySnapshot) => {
            setMessages(prev => [
                ...prev, 
                ...querySnapshot.map(doc => ({
                    mid: doc.id, 
                    ...doc.data(),
                })),
            ]);
        });
    });

    // Unsubscribe when you unmount
    return () => unsubscribe();
}, [])

Upvotes: 1

Related Questions