【问题标题】:I wonder if this really is the correct way to use onAuthStateChanged我想知道这是否真的是使用 onAuthStateChanged 的​​正确方法
【发布时间】:2021-01-30 01:22:58
【问题描述】:

关注这个react-firestore-tutorial 和GitHub code。我想知道以下是否是使用onAuthStateChanged 的正确方法,或者如果我理解了这个不正确的方法,我只是对这是正确的方法感到困惑。

CodeSandBox 使用 apikey 与 Firebase 的测试帐户完全连接!!所以你可以试试我的意思,我可以学习这个。

(注意:Firebase 会阻止 Codesandbox 网址,即使它位于授权域中,对此很抱歉,但您仍然可以看到代码)

t {code: "auth/too-many-requests", message: "我们已阻止所有 由于异常活动而从该设备发出的请求。稍后再试。”, 一个:空}一个:

请注意,这是一个完全成熟的 Reactjs-Vanilla 高级网站,仅使用;
反应 16.6
反应路由器 5
Firebase 7

在代码中,Firebase.js 有这个onAuthStateChanged,它从两个不同的组件调用,也被调用了多次,据我所知,应该只设置一次,然后监听它的回调。多次调用它不会创建很多听众吗?

有人可以看看这段代码在 Reactjs 中处理 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;

这两个rect-higher-order组件:

第一个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;

还有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;

【问题讨论】:

    标签: reactjs authentication firebase-authentication one-time-binding


    【解决方案1】:

    这是正常的。 onAuthStateChanged 接收一个观察者函数,如果登录成功则传递一个用户对象,否则不传递。

    作者已将onAuthStateChanged 包装为更高阶的函数——onAuthUserListener。 HOF 接收两个参数作为函数,next 和 fallback。这两个参数是创建 HOC 的 withAuthentication 和 withAuthorization 时的唯一区别。

    前者的next参数是在localStorage上存储用户数据的函数

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

    而后者的next参数根据条件重定向到新的路由。

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

    所以,我们只是根据不同的需求传递不同的观察者函数。我们将包装 HOC 的组件将在实例化时获得它们各自的观察者函数。观察者函数根据身份验证状态更改事件提供不同的功能。因此,要回答您的问题,它是完全有效的。

    参考:

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

    【讨论】:

    • 谢谢,我理解流程,但是当在 firebase.js 文件中只有一个 onAuthUserListener 监听器注册函数和 this.auth.onAuthStateChanged(authUser =&gt; {... 连接两个 HOC 时,我无法理解。我在想他们会导致 2 个听众被注册。我想我明白了,只有一个听众,两个 HOC 都在使用这个单一的。在 Android java 中,同样更容易看出它是如何工作的,谢谢
    • 抱歉回复晚了。我们只有一个onAuthUserListener 的原因是因为它是一个 HOF。 HOF 自己不会做任何事情。它返回一个做某事的函数。这里的事情是将观察者函数附加到onAuthStateChanged 方法,这是由两个 HOC 完成的。所以你是正确的关于 2 个听众正在注册。一个用于withAuthorization,另一个用于withAuthentication。重要的是要知道onAuthStateChanged 在onAuthUserListener 中定义时没有注册。只有在调用onAuthUserListener HOF 时才会注册。
    猜你喜欢
    • 1970-01-01
    • 2011-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 2021-01-04
    • 1970-01-01
    相关资源
    最近更新 更多