skip to Main Content

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


  1. You can create two wrapper components for AuthenticatedApp and UnauthenticatedApp 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 the AuthenticatedApp. 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/

    Login or Signup to reply.
  2. 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 an if 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, the useCollection hook accepts a firestore.Query or null as its first argument. As this value is fed to useRef() internally, you can change its value on each render as needed.

    const recentForumPostsQuery = user
        ? query(collection(db, "forum_posts", where("userId", '==', user.userFirebase.uid)))
        : null; // maybe fallback to a public feed?
    
    const [recentForumPosts, loadingRecentForumPosts, errorRecentForumPosts] =
        useCollection(recentForumPostsQuery); // useCollectionData may also be of use
    
    // query is null?  recentForumPosts will always be undefined
    // query is given? recentForumPosts will be undefined until data is successfully fetched,
    //                 where it will be a QuerySnapshot
    
    if (loadingRecentForumPosts)
      return null; // example: hide until data is loaded
    
    if (!recentForumPosts)
      return (
        <div class="error">
          You must login first to see your recent posts!
        </div>
      );
    
    // TODO: render posts
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search