How to delay React Firebase Hooks until it is known if user is logged in (similar to how enabled works on React Query useQuery)
I need to get data from firebase, but only want to get the data if the user is logged in. In React Query, there is an option "enabled" property that can be passed to delay the call until a certain condition is true. This is exactly what I need but for the React Firebase Hooks.
Take the code below:
const [recentForumPosts, laodingRecentForumPosts, errorRecentForumPosts] = useCollection(query(collection(db, "forum_posts", where("userId", '==', user.userFirebase.uid))));
Its using the users’ uid to get the data from firestore, but this may be null || undefined (if the user is not logged in). However the API call with still attempt to get this info with null id resulting in a wasted API call and error in the log.
I’ve tried putting it in a useEffect but react throws an error that hooks cannot be used inside a callback.
useEffect(() => { const [recentForumPosts, laodingRecentForumPosts, errorRecentForumPosts] = useCollection(query(collection(db, "forum_posts", where("userId", '==', user.userFirebase.uid)))); }, [user])
I’ve also tried putting an IF statment before the hook but react throws an error that a React Hook cannot be used conditionally.
if (user) { const [recentForumPosts, laodingRecentForumPosts, errorRecentForumPosts] = useCollection(query(collection(db, "forum_posts", where("userId", '==', user.userFirebase.uid))));}
I am using context to store the user object at the top level of the app and using it throughout the app. Essentially if its null or undefined, then user is not logged in, and if it has data, user is logged in.
This seems like a pretty common use case for React Firebase Hooks, (Getting data that belongs to a user) but I am struggling to conditionally call this this hook if they are logged in or not.
2
Answers
You can create two wrapper components for
AuthenticatedApp
andUnauthenticatedApp
and conditionally render one or the other depending on whether the user is present and move the custom hook so that it is only called inside theAuthenticatedApp
. By moving the hook into a conditionally rendered child component, you can achieve your use case.See a detailed explanation of this pattern here:
https://www.robinwieruch.de/react-conditional-hooks/
As you’ve identified, each hook must always be called in the exact same order on each render which means you can’t call
useX
inside of anif
block. So instead of looking at changing when the hook is called, you should instead look at the arguments passed into that hook. In particular, theuseCollection
hook accepts afirestore.Query
ornull
as its first argument. As this value is fed touseRef()
internally, you can change its value on each render as needed.