javascriptreactjsfirebasefirebase-authentication

Is there any way in React to check if Firebase user exists before redirecting user?


I'm making an app, where I use NextJS along with Firebase, Fireauth. The problem is that the user isn't available as soon as the page reloads or loads, it takes time to load, till then useEffect also fails to identify if user exists or not and just decides user doesn't exist.

This is my code

import { useAuth } from '/pages/contexts/AuthContexts';

const { user } = useAuth();
    const router = useRouter();

    const [loading, setLoading] = useState(true);

    useEffect(() => {
        console.log('updating user')
        if (user) {
            console.log(user);
            setLoading(false)
        } else {
            console.log('no user')
        }
    }, [user, router]);
    

    useEffect(() => {
        if (!loading && typeof user !== 'undefined') {
            console.log('yes user')
        }else{
            console.log('no user')
        }
    }, [loading]);

Here i first see no user, then after a while i see yes user, the loading state isnt helping at all

This is my useAuth file

// contexts/AuthContext.js
import { createContext, useContext, useState, useEffect } from 'react';
import { onAuthStateChanged } from 'firebase/auth';
import { auth } from 'flubel/firebase';

const AuthContext = createContext();

export const AuthProvider = ({ children }) => {
  const [user, setUser] = useState(null);

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      setUser(user);
    });

    return () => {
      unsubscribe();
    };
  }, []);

  return (
    <AuthContext.Provider value={{ user, setUser }}>
      {children}
    </AuthContext.Provider>
  );
};

export const useAuth = () => {
  return useContext(AuthContext);
};

I tried creating multiple states but they all return no user no matter how I handle the states, I can't use setTimeout because, slow internet connection could also be a problem.


Solution

  • While the Firebase Authentication client keeps the credentials in local storage, it needs to check with the server whether those credentials and account are valid (for example: it could've been disabled). And since that call takes time:

    There is nothing in the Firebase Authentication SDK to change this behavior, as it it working correctly on that level.


    But in an application you may be willing to make another trade-off. For example, if the user was signed in before - most of the time the above flow will complete successfully. So on an application level you can decide to assume that the sign-in will completely successfully in that scenario.

    If that is something you're interested in, you can implement it was follows:

    1. When the user signs in, store a value in synchronous local storage to indicated this.
    2. When the page loads, synchronously check for this value and if it is present, redirect to the "you're signed in" UI. Don't show actual user data at this point yet (as you'll want to wait for the Auth client to give the green light for that), but you can show the signed-in UI.
    3. If the Auth client says there is no user (in the onAuthStateChanged callback), revers the decission and redirect to the "you're not signed in" UI. This will result in a UI flash, but it'll be much less common.

    Also see When the page is reloaded, firebase.auth.currentUser returns null, where I explained this before.