当前位置: 首页 > 知识库问答 >
问题:

React Redux Firebase-onAuthStateChanged延迟阻止使用生命周期方法

太叔永新
2023-03-14

我正在React Redux应用程序中实施Firebase身份验证。

问题:我遇到了一个问题,该问题阻止我使用 React 的组件生命周期方法来支持条件渲染。

在页面之间导航时,当加载每个页面/组件时,初始cUser(当前用户)状态为空。这是因为在等待Firebase的“onAuthStateChanged”方法解析和在Redux中更新cUser(当前用户)状态时有一点延迟。组件在状态有机会使用当前用户更新之前加载。这并不奇怪,因为这是一个异步进程。

问题:最好的处理方法是什么?

我有很多方法可以解决这个问题,但是使用组件生命周期方法会更有效。

我看到过2016年的相关帖子指示检查localStorage,但在访问localStorage时,似乎没有任何与Firebase相关的内容。我假设Firebase不再在localStorage中存储用户数据

代码:

我的应用组件调用“onAuthStateChanged”Firebase 方法。

import React, { Component } from 'react';
import { BrowserRouter, Route } from 'react-router-dom';
import { connect } from 'react-redux';

import { firebase } from '../firebase';
import * as actions from '../actions';
import '../styles/styles.css';
import { LOBBY, HISTORY, TOPS, LANDING, SIGN_UP, SIGN_IN, FORGOT_PASSWORD, ACCOUNT, SIGN_OUT } from '../config/routes';

import Header from './Header';
import Footer from './Footer';
import Lobby from './Lobby';
import History from './History';
import Tops from './Tops';

import Landing from './registration/Landing';
import SignIn from './registration/SignIn';
import SignUp from './registration/SignUp';
import SignOut from './registration/SignOut';
import Account from './Account';
import ForgotPassword from './registration/ForgotPassword';


class App extends Component {
  componentDidMount() {
    console.log(Object.keys(localStorage));
    const { signOutUser, updateUserAuth } = this.props;

    firebase.auth.onAuthStateChanged((authUser) => {
      if (authUser) {
        updateUserAuth(authUser);
      } else {
        signOutUser();
      }
    });
  }
  checkAuth() {
    if (this.props.cUser) {
      return <Header />;
    }
    return null;
  }

  render() {
    console.log('cUser: from APP', this.props.cUser);
    return (
      <div className="lightGray">
        <div className="container ">
          <BrowserRouter>
            <div>
              {this.checkAuth()}
              <Route exact path={LOBBY} component={Lobby} />
              <Route exact path={HISTORY} component={History} />
              <Route exact path={TOPS} component={Tops} />

              <Route exact path={LANDING} component={Landing} />
              <Route exact path={SIGN_UP} component={SignUp} />
              <Route exact path={SIGN_IN} component={SignIn} />
              <Route exact path={SIGN_OUT} component={SignOut} />
              <Route exact path={FORGOT_PASSWORD} component={ForgotPassword} />
              <Route exact path={ACCOUNT} component={Account} />
              <Footer />
            </div>
          </BrowserRouter>
        </div>
      </div>
    );
  }
}
function mapStateToProps({ cUser }) {
  return { cUser };
}

export default connect(mapStateToProps, actions)(App);

更新当前用户状态的操作。

export const updateUserAuth = user => async (dispatch) => {
  try {
    const payload = {
      displayName: user.displayName,
      email: user.email,
      emailVerified: user.emailVerified,
      refreshToken: user.refreshToken,
      userId: user.uid,
    };
    return dispatch({ type: CURRENT_USER, payload });
  } catch (error) {
    console.log('error: ', error);
    return error;
  }
};

帐户页面上的cUser(当前用户)将始终为空。

import React, { Component } from 'react';
import { connect } from 'react-redux';

import * as actions from '../actions';

class Account extends Component {
  componentWillMount() {
    if (this.props.cUser) {// always null
      this.props.getUserData(this.props.cUser.idToken); 
    }
  }
  render() {
    return (
      <div className="">
        <div className="row valign-wrapper section">
          <h1 className=" bigHeader">Account</h1>
          <div className="col s2 right-align" />
        </div>
      </div>
    );
  }
}
function mapStateToProps({ cUser }) {
  return { cUser };
}

export default connect(mapStateToProps, actions)(Account);

firebase实现

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

const prodConfig = {
  apiKey: 'xxxx',
  authDomain: 'xxx',
  databaseURL: 'xxx',
  projectId: 'xxx',
  storageBucket: 'xxx',
  messagingSenderId: 'xxx',
};

const devConfig = {
  apiKey: 'xxxx',
  authDomain: 'xxx',
  databaseURL: 'xxx',
  projectId: 'xxx',
  storageBucket: 'xxx',
  messagingSenderId: 'xxx',
};

const config = process.env.NODE_ENV === 'production'
  ? prodConfig
  : devConfig;

if (!firebase.apps.length) {
  firebase.initializeApp(config);
}

export const auth = firebase.auth();

共有1个答案

曾嘉言
2023-03-14

通过在本地存储中存储userId解决了这个问题。

firebase.auth.onAuthStateChanged((authUser) => {
      if (authUser) {
        localStorage.setItem('userId', authUser.uid);
        updateUserAuth(authUser);
      } else {
        localStorage.removeItem('userId');
        signOutUser();
      }
    });
 类似资料:
  • 方法的标注和函数类似: struct Owner(i32); impl Owner { // 标注生命周期,就像独立的函数一样。 fn add_one<'a>(&'a mut self) { self.0 += 1; } fn print<'a>(&'a self) { println!("`print`: {}", self.0); } } fn

  • 用法 组件和虚拟 DOM 节点都有生命周期方法,也叫钩子,它们会在 DOM 元素的生命周期的对应时期被调用。 // 组件中的钩子 var ComponentWithHook = { oninit: function(vnode) { console.log("initialize component") }, view: function() { return "hello

  • 问题内容: 我是React / Redux的新手,状态有问题。 TrajectContainer.jsx 当reducer返回新状态时,组件将使用新数据重新呈现。 但是:如果删除componentWillReceiveProps函数,则render()函数将具有旧状态。 我检查了mapStateToProps中收到的数据,这是新的新状态。所以我不明白为什么我需要componentWillRecei

  • 问题内容: 在哪里进行调用将使我的状态失水的API调用的最佳位置是哪里?构造函数或生命周期方法之一,例如ComponentWillMount? 问题答案: 最好从生命周期方法进行api调用,反应文档也建议相同。 根据DOC: componentDidMount: 挂载组件后立即调用componentDidMount()。需要DOM节点的初始化应该在这里进行。 如果需要从远程端点加载数据,这是实例化

  • 注:本文档提供的生命周期指的是 Universal App 的生命周期,它依赖 rax-app 提供的 runApp方法。 App 级生命周期 launch  在 App 启动时触发 使用生命周期 你可以使用 rax-app 提供的 useAppLaunch 来注册 App 级别的生命周期。 示例: import { useAppLaunch } from 'rax-app'; useAppLa

  • 我们大致为WebAPplication设计了4个生命周期: 请求初始化其实就是从URL中解析提取出{module}, {action}, {method}; 然后再根据{module}, {action}, {method}找到对应的Controller文件; 然后再调用对应的{method},完了之后再发送响应。当然响应的过程中肯定是要顺带着解析下模板标签啦。 恩,这就完了,貌似感觉很简单啊。