简体   繁体   中英

I wonder if this really is the correct way to use onAuthStateChanged

Following this react-firestore-tutorial and the GitHub code . I wonder if the following is correct way to use the onAuthStateChanged or if I have understod this incorrect I'm just confused if this is the right way.

CodeSandBox fully connect with a test-account with apikey to Firebase!! so you can try it what I mean and I can learn this.

(NOTE: Firebase is blocking Codesandbox url even it's in Authorised domains, sorry about that but you can still see the code)

t {code: "auth/too-many-requests", message: "We have blocked all requests from this device due to unusual activity. Try again later.", a: null}a:

Note this is a Reactjs-Vanilla fully fledge advanced website using only;
React 16.6
React Router 5
Firebase 7

Here in the code the Firebase.js have this onAuthStateChanged and its called from two different components and also multiple times and what I understand one should only set it up once and then listen for it's callback. Calling it multiple times will that not create many listeners?

Can someone have a look at this code is this normal in Reactjs to handle onAuthStateChanged ? (src\\components\\Firebase\\firebase.js)

import app from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';

class Firebase {
  constructor() {
    app.initializeApp(config);

   .......
  }

  .....

  onAuthUserListener = (next, fallback) =>
    this.auth.onAuthStateChanged(authUser => {
      if (authUser) {
        this.user(authUser.uid)
          .get()
          .then(snapshot => {
            const dbUser = snapshot.data();

            // default empty roles
            if (!dbUser.roles) {
              dbUser.roles = {};
            }

            // merge auth and db user
            authUser = {
              uid: authUser.uid,
              email: authUser.email,
              emailVerified: authUser.emailVerified,
              providerData: authUser.providerData,
              ...dbUser,
            };

            next(authUser);
          });
      } else {
        fallback();
      }
    });

  user = uid => this.db.doc(`users/${uid}`);

}

export default Firebase;

This two rect-higher-order Components:

First withAuthentication : (src\\components\\Session\\withAuthentication.js)

import React from 'react';

import AuthUserContext from './context';
import { withFirebase } from '../Firebase';

const withAuthentication = Component => {
  class WithAuthentication extends React.Component {
    constructor(props) {
      super(props);

      this.state = {
        authUser: JSON.parse(localStorage.getItem('authUser')),
      };
    }

    componentDidMount() {
      this.listener = this.props.firebase.onAuthUserListener(
        authUser => {
          localStorage.setItem('authUser', JSON.stringify(authUser));
          this.setState({ authUser });
        },
        () => {
          localStorage.removeItem('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;

And withAuthorization : (src\\components\\Session\\withAuthorization.js)

import React from 'react';
    import { withRouter } from 'react-router-dom';
    import { compose } from 'recompose';
    
    import AuthUserContext from './context';
    import { withFirebase } from '../Firebase';
    import * as ROUTES from '../../constants/routes';
    
    const withAuthorization = condition => Component => {
      class WithAuthorization extends React.Component {
        componentDidMount() {
          this.listener = this.props.firebase.onAuthUserListener(
            authUser => {
              if (!condition(authUser)) {
                this.props.history.push(ROUTES.SIGN_IN);
              }
            },
            () => this.props.history.push(ROUTES.SIGN_IN),
          );
        }
    
        componentWillUnmount() {
          this.listener();
        }
    
        render() {
          return (
            <AuthUserContext.Consumer>
              {authUser =>
                condition(authUser) ? <Component {...this.props} /> : null
              }
            </AuthUserContext.Consumer>
          );
        }
      }
    
      return compose(
        withRouter,
        withFirebase,
      )(WithAuthorization);
    };
    
    export default withAuthorization;

This is normal. onAuthStateChanged receives an observer function to which a user object is passed if sign-in is successful, else not.

Author has wrapped onAuthStateChanged with a higher order function – onAuthUserListener . The HOF receives two parameters as functions, next and fallback . These two parameters are the sole difference when creating HOC's withAuthentication and withAuthorization .

The former's next parameter is a function which stores user data on localStorage

localStorage.setItem('authUser', JSON.stringify(authUser));
this.setState({ authUser });

while the latter's next parameter redirects to a new route based on condition.

if (!condition(authUser)) {
  this.props.history.push(ROUTES.SIGN_IN);
}

So, we are just passing different observer function based on different requirements. The component's we will be wrapping our HOC with will get their respective observer function on instantiation. The observer function are serving different functionality based on the auth state change event. Hence, to answer your question, it's completely valid.

Reference:

  1. https://firebase.google.com/docs/reference/js/firebase.auth.Auth#onauthstatechanged
  2. https://reactjs.org/docs/higher-order-components.html

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