How do I use the Firebase onAuthStateChange with the new React Hooks?

11,905

You can write a Custom Hook which registers an effect and returns the auth state

const useFirebaseAuthentication = (firebase) => {
    const [authUser, setAuthUser] = useState(null);

    useEffect(() =>{
       const unlisten = firebase.auth.onAuthStateChanged(
          authUser => {
            authUser
              ? setAuthUser(authUser)
              : setAuthUser(null);
          },
       );
       return () => {
           unlisten();
       }
    }, []);

    return authUser
}

export default useFirebaseAuthentication;

and in any Component you can use it like

const MyComponent = (props) => {
   const firebase = useContext(FirebaseContext);
   const authUser = useFirebaseAuthentication(firebase);
   
   return (...)
}

Index.jsx will have this code in it

ReactDOM.render( 
   <FirebaseProvider> 
      <App /> 
   </FirebaseProvider>, 
   document.getElementById('root')); 

This Firebase Provider is defined like this,

import Firebase from './firebase';

const FirebaseContext = createContext(); 
export const FirebaseProvider = (props) => ( 
   <FirebaseContext.Provider value={new Firebase()}> 
      {props.children} 
   </FirebaseContext.Provider> 
); 
Share:
11,905

Related videos on Youtube

Tristan Trainer
Author by

Tristan Trainer

Currently work as a full stack developer at a start up company. Working with technologies including .Net and React. Languages include C#, Javascript (+Typescript) and Ruby.

Updated on June 04, 2022

Comments

  • Tristan Trainer
    Tristan Trainer almost 2 years

    I am using Firebase to authenticate users for my application. I have created the SignIn and SignUp forms and can successfully create new users and sign in with stored users. However the issue comes with maintaining the user logged in state after a Reload.

    The way I have seen it done in tutorials is to use a HOC like the following to check if the current user is logged in.

    const withAuthentication = Component => {
      class WithAuthentication extends React.Component {
        constructor(props) {
          super(props);
    
          this.state = {
            authUser: null,
          };
        }
    
        componentDidMount() {
          this.listener = this.props.firebase.auth.onAuthStateChanged(
            authUser => {
              authUser
                ? this.setState({ authUser })
                : this.setState({ authUser: null });
            },
          );
        }
    
        componentWillUnmount() {
          this.listener();
        }
    
        render() {
        return (
          <AuthUserContext.Provider value={this.state.authUser}>
            <Component {...this.props} />
          </AuthUserContext.Provider>
          );
        }
      }
    
      return withFirebase(WithAuthentication);
    };
    
    export default withAuthentication;
    

    However I am looking to use the new React Hooks to remove the need for HOCs. I have already removed the withFirebase() HOC by using the React Context and useContext(FirebaseContext) to access a single instance of Firebase. Is there a way using the new hooks to mimic this withAuthentication HOC within components that I create?

    I am using this tutorial

    https://www.robinwieruch.de/complete-firebase-authentication-react-tutorial/

    The section titled "Session Handling with Higher-Order Components" contains this part.

    Thanks!

    • Jeff
      Jeff about 5 years
      one option is to use the react-firebase-hooks library, which has support for onAuthStateChange through its useAuthState hook
    • Tristan Trainer
      Tristan Trainer about 5 years
      Thanks Jeff, I did look into this, however I want to reduce the number of dependencies my project has as it will have minimal maintenance in future so I don't want to have to worry too much about breaking changes!
    • Mel
      Mel over 4 years
      @TristanTrainer - did you figure this out? I'm struggling with the same problem stackoverflow.com/questions/59977856/…
  • 1nullpointer
    1nullpointer about 5 years
    Beginner Question , am following the same tutorial . How did you write useContext(FirebaseContext) function .Can you please share the code if possible. Also how do you apply it if it is not similar to the provided in the tutorials . Thanks
  • Shubham Khatri
    Shubham Khatri about 5 years
    @1nullpointer, useContext is a hook provided by react out of the box which you can use by importing like import {useContext} from 'react';
  • 1nullpointer
    1nullpointer about 5 years
    am trying to follow the tutorials but write the code with hooks . If am providing the context at the App level component , where do i use this code . Thats where my confusion began . : const firebase = useContext(FirebaseContext); const authUser = useFirebaseAuthentication(firebase); Or should I wrap one into another .'Provide Firebase in React' Section in the tutorials specifically
  • Shubham Khatri
    Shubham Khatri about 5 years
    @1nullpointer You will use useContext in components where you have FirebaseContext.Consumer in render of HOC.
  • 1nullpointer
    1nullpointer about 5 years
    Ok, that means I need not wrap the whole render return stmt like that ? <FirebaseContext.Consumer> {firebase => { return <div>I've access to Firebase and render something.</div>; }} </FirebaseContext.Consumer>
  • Shubham Khatri
    Shubham Khatri about 5 years
    yes, you just need usecontext and that return you what the render prop of FirebaaseContext.Consumer returns in callback
  • 1nullpointer
    1nullpointer about 5 years
    am getting Unhandled Rejection (TypeError): Firebase__WEBPACK_IMPORTED_MODULE_6_.default is not a constructor @ <FirebaseContext.Provider value={new firebase()}> Am doing import firebase from 'firebase/app' firebase.initializeApp(config) export default firebase
  • 1nullpointer
    1nullpointer about 5 years
    If I change it to <FirebaseContext.Provider value={firebase}> then i get firebase.auth.onAuthStateChanged is not a function error
  • 1nullpointer
    1nullpointer about 5 years
    Never mind , got it working now by changing to firebase.auth().onAuthStateChanged() and <FirebaseContext.Provider value={firebase}>
  • 1nullpointer
    1nullpointer about 5 years
    Question , can I merge below 2 lines so that i have a single line of code in all my consumer classes . Or does it vary based on context ? const firebase = useContext(FirebaseContext); const authUser = useFirebaseAuthentication(firebase);
  • Shubham Khatri
    Shubham Khatri about 5 years
    You can craete a custom hook that calls these two hooks and returns the result, much like you did for useFirebaseAuthentication
  • ConorLuddy
    ConorLuddy almost 5 years
    Thanks for this answer - it clarified a few things. FWIW, I ended up one-lining the useEffect, like so: useEffect(() => firebase.auth.onAuthStateChanged(onChange), [])
  • Faris
    Faris almost 5 years
    @ConorLuddy I think that might cause a memory leak because you are not closing the listener.
  • Faris
    Faris over 4 years
    Does that mean when 'onAuthStateChanged' fires, MyComponent will rerender? (the value of authUser would update)
  • ConorLuddy
    ConorLuddy over 4 years
    @Faris - my understanding is that useEffect will run whatever method it returns, which is the un-listen from onAuthStateChanged. Open to correction though...
  • Faris
    Faris over 4 years
    @ConorLuddy yes, I think that is the case. Thank you for your reply.
  • Mel
    Mel over 4 years
    @ShubhamKhatri - I'm stuck with my efforts to implement your solution - do you have an advice for how to get past these config issues? stackoverflow.com/questions/59977856/… Thank you
  • Badmaash
    Badmaash over 2 years
    @ShubhamKhatri Why are you not using empty brackets as dependency? You don't want to setup a listener again if state changes? Setting a listener just once is enough.
  • Shubham Khatri
    Shubham Khatri over 2 years
    @Badmaash Thank you for pointing it out. I missed it in my answer
  • metamorph_online
    metamorph_online over 2 years
    thank you!!! really appreciate your answer