Home > Back-end >  Value of state variable different inside useEffect hook (firestore onSnapshot callback)
Value of state variable different inside useEffect hook (firestore onSnapshot callback)

Time:05-27

I am running into an issue where a state value (loadMore) inside a firestore's onSnapshot's callback is different to what it is when entering the hook, and I'm unable to understand why. Perhaps some smarter soul out there will be able to spot the problem:

   useEffect(() => {
     console.log("loadMore", loadMore); // returns false
     if (cursor) {
      onSnapshot(
        query(
          firestore
            .collectionGroup("posts")
            .orderBy("createdAt", "desc")
            .startAfter(cursor)
            .limit(POSTS_PER_REQUEST_LIMIT)
        ),
        (querySnapshot) => {
          console.log("loadMore", loadMore); // returns true
        }
      );
    }
    }, [cursor, loadMore]);

As you can see, the problem is that, as expected, loadMore === false when the useEffect hook is fired but the onSnapshot's callback function still believes it is true. Why? I will keep searching for answers but, in the meantime, will be questioning my own sanity. Thanks to anyone who can help.

CodePudding user response:

It appears that onSnapshot's success listener has stale values. This can be because it's an outdated listener which needs to be unsubscribed from when one of the dependencies changes.

Firestore's onSnapshot returns a function that you can use to unsubscribe / clean up outdated callbacks.

You can return that function in useEffect and it should fix your issue:

useEffect(() => {
  if (cursor) {
   const unsubscribe = onSnapshot(
     query(
       firestore
         .collectionGroup("posts")
         .orderBy("createdAt", "desc")
         .startAfter(cursor)
         .limit(POSTS_PER_REQUEST_LIMIT)
     ),
     (querySnapshot) => {
       console.log("loadMore", loadMore); // should be correct now
     }
   );
   return unsubscribe;
 }
}, [cursor, loadMore]);

You can read more about effect cleanup in the React documentation: https://reactjs.org/docs/hooks-effect.html#effects-with-cleanup

  • Related