onAuthStateChanged似乎不适用于React上下文api

时间:2019-02-02 11:59:18

标签: javascript reactjs firebase firebase-authentication

我目前正在关注Robin Wieruch的著作《用Firebase进行反应的道路》。我的问题是,当我刷新从Context API使用的页面时,Firebase的authUser变为空。

这是我的app.js

import Navigation from './Navigation';
import LandingPage from './Landing';
import AccountPage from './Account';
import withAuthentication from './withAuthentication';

import * as routes from '../constants/routes';

const App = () =>
        <Router>
        <div>
        <h3 className="alt-h3" style={{textAlign: "center"}}>Soundyladder</h3>

          <Navigation />
          <hr/>

          <Route
            exact path={routes.LANDING}
            component={LandingPage}
          />


              <Route
            exact path={routes.ACCOUNT}
            component={AccountPage}
          />
        </div>
      </Router>

export default withAuthentication(App);

如您所见,app.js使用的是高级组件。

withAuthentication.js:

import AuthUserContext from './AuthUserContext';

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

            this.state = {
                authUser: null
            };
        }

        componentDidMount() {

            firebase.auth.onAuthStateChanged(authUser => {
                authUser != null ? this.setState({ authUser }) : this.setState({ authUser: null });

            });

        }

        render() {
            const { authUser } = this.state;
            console.log(this.state);
            return (

                <AuthUserContext.Provider value={authUser}>
                    <Component { ...this.props } />
                </AuthUserContext.Provider>
            )
        }
    }

    return withAutnetication;
}

export default withAuthentication;

正如您在此处看到的那样,我提供了Context API,以便App.js下的每个组件都可以从中使用它。

这是AuthUserContext:

import React from 'react';

const AuthUserContext = React.createContext(null);

export default AuthUserContext;

问题是,当我访问帐户页面,然后刷新页面时,authUser变为空。

Account.js:

const AccountPage = () =>
    <AuthUserContext.Consumer>
        {authUser =>

            <div>
                <h1>Account: {authUser.email}</h1>
                <PasswordForgetForm />
                <PasswordChangeForm />
            </div>
        }
    </AuthUserContext.Consumer>

    export default AccountPage;

但是,当我在LandingPage上并刷新页面时,authUser不会为空。

这是我的目标网页:

const LandingPage = () =>
    <div>
        <h1>Landing Page</h1>
    </div>

export default LandingPage;

但是,如果我尝试从登录页面的Context API中使用authUser,就像在帐户页面中一样,则会遇到相同的错误:authUser变为null。

Context API似乎有问题吗?

1 个答案:

答案 0 :(得分:0)

我不确定“使用Firebase做出反应的道路”一书中的身份验证策略是什么,但是可以通过这种方式简单地解释您遇到的问题。

重新加载帐户页面

在第一次渲染时(刷新页面后),React首先安装所有可用内容。然后,它在您的componentDidMount HOC中触发withAuthentication方法。

这意味着,在第一次渲染时(刷新页面后立即),上下文值authUsernull

React引发错误(这是正确的吗?),然后停止执行。因此从未到达您的componentDidMount在HOC。

Cannot read property 'email' of null

登陆页面重新加载

在这里,React不会停止执行,因为它可以呈现所有内容。然后将触发componentDidMount在HOC和火力获取用户(异步)。通过在导航到用户已被加载的“帐户页面”,因此你authUser是不再null

Potentail简单修复

再次不知道什么样的验证策略的书提供,而是去解决这个问题,你可以简单地做这些方针的东西在你的HOC

render() {
  const { authUser } = this.state;

  if (!authUser) {
    return null;
  }

  return (
    <AuthUserContext.Provider value={authUser}>
      <Component { ...this.props } />
    </AuthUserContext.Provider>
  )
}

或者您可以像这样在“帐户页面”中添加支票

<h1>Account: {authUser ? authUser.email : null}</h1>

一个非常粗糙的例子可以发现in this codesandbox。我用setInterval代替火力AUTH方法。让我知道它有助于解决问题。