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