简体   繁体   中英

How to set up firebase auth onAuthStateChanged() listener run when React app is loaded?

I'm trying set up the Firebase auth listener on my top level component App in order to provide the authUser object via React context to all other components.

I'm currently doing this:

function App() {
  console.log('Rendering App...');
  const [authUser,setAuthUser] = useState(null);
  const [authWasListened,setAuthWasListened] = useState(false);

  useEffect(()=>{
    console.log('Running App useEffect...');
    return firebase.auth().onAuthStateChanged(
      (authUser) => {

        console.log(authUser);
        console.log(authUser.uid);

        if(authUser) {
          setAuthUser(authUser);
          setAuthWasListened(true);
        } else {
          setAuthUser(null);
          setAuthWasListened(true);
        }

      }
    );

  },[]);

  return(
    authWasListened ?
    <Layout/>
    : <div>Waiting for auth...</div>
  );

}

But I'm getting the log output:

Rendering App...
Running App useEffect...

It seems that I'm setting up the listener but it doesn't run at first, therefore it's not getting the current auth state (which is null, since I don't even have a login form yet). It seems like it's waiting for a change to occur.

Shouldn't the authListener get the current authUser state at first, and then listen to changes? What am I doing wrong?

UPDATE

I've found out what I was doing wrong. The useEffect should return a function to clear the listener on unmount and not a function call, as I was trying to do above. So my listener was never being set up.

This is working as intended now:

useEffect(()=>{
    console.log('Running App useEffect...');
    const authListener = firebase.auth().onAuthStateChanged(
      (authUser) => {

        console.log(authUser);
        console.log(authUser.uid);

        if(authUser) {
          setAuthUser(authUser);
          setAuthWasListened(true);
        } else {
          setAuthUser(null);
          setAuthWasListened(true);
        }

      }
    );
    return authListener;  // THIS MUST BE A FUNCTION, AND NOT A FUNCTION CALL

  },[]);

See https://reactjs.org/docs/hooks-effect.html#example-using-hooks-1

Why did we return a function from our effect? This is the optional cleanup mechanism for effects. Every effect may return a function that cleans up after it. This lets us keep the logic for adding and removing subscriptions close to each other. They're part of the same effect!

When exactly does React clean up an effect? React performs the cleanup when the component unmounts. However, as we learned earlier, effects run for every render and not just once. This is why React also cleans up effects from the previous render before running the effects next time. We'll discuss why this helps avoid bugs and how to opt out of this behavior in case it creates performance issues later below.

And see Set an authentication state observer and get user data

Try the following code.

function App() {
  console.log('Rendering App...');
  const [authUser,setAuthUser] = useState(null);
  const [authWasListened,setAuthWasListened] = useState(false);

  useEffect(()=>{
    console.log('Running App useEffect...');
    firebase.auth().onAuthStateChanged(
      (authUser) => {

        console.log(authUser);
        console.log(authUser.uid);

        if(authUser) {
          setAuthUser(authUser);
          setAuthWasListened(true);
        } else {
          setAuthUser(null);
          setAuthWasListened(true);
        }

      }
    );
  },[]);

  return(
    authWasListened ?
    <Layout/>
    : <div>Waiting for auth...</div>
  );

}

The listener is not immediate. The change in state might take some time from the moment the page is first loaded. If you want an immediate check to see if a user is signed in, you can use currentUser , but again, it might take some time for that to update, so the listener is the better choice.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM