简体   繁体   English

如何在 React 应用程序中处理 Firebase onAuthStateChanged 并相应地路由用户?

[英]How to handle Firebase onAuthStateChanged in a React app and route users accordingly?

I'm working on a React web app that is integrated with Firebase and I'm trying to authenticate my users.我正在开发与 Firebase 集成的 React web 应用程序,我正在尝试对我的用户进行身份验证。 I have setup my route to display Home component if the user is authenticated and the Login page otherwise.如果用户通过身份验证,我已经设置了我的路由以显示主页组件,否则显示登录页面。 But when my app first loads, it shows the Login page and it takes a second or two for it to recognize the user has actually been authenticated and then it switches to the Home page.但是,当我的应用程序首次加载时,它会显示登录页面,它需要一两秒钟的时间来识别用户实际上已经过身份验证,然后切换到主页。 It just seems messy and I'm guessing I'm not handling onAuthStateChanged quite well or fast enough.它看起来很乱,我猜我对 onAuthStateChanged 的处理不够好或不够快。 In my App component, I am subscribed to a ReactObserver that signals when auth state has changed.在我的 App 组件中,我订阅了一个 ReactObserver,它会在 auth state 发生更改时发出信号。 What can I do to avoid this weird behaviour?我该怎么做才能避免这种奇怪的行为?

My App.js :我的App.js

import {BrowserRouter, Route} from "react-router-dom";
import Home from "./Home";
import Login from "./Login";
import {loggedIn, firebaseObserver} from "../firebase";
import {useEffect, useState} from "react";

export default function App() {
    const [authenticated, setAuthenticated] = useState(loggedIn())

    useEffect(() => {
        firebaseObserver.subscribe('authStateChanged', data => {
            setAuthenticated(data);
        });
        return () => { firebaseObserver.unsubscribe('authStateChanged'); }
    }, []);

   return <BrowserRouter>
             <Route exact path="/" render={() => (authenticated ? <Home/> : <Login/>)} />
          </BrowserRouter>;
}

My firebase.js :我的firebase.js

import firebase from "firebase/app";
import "firebase/auth";
import "firebase/firestore";
import ReactObserver from 'react-event-observer';

const firebaseConfig = {
    apiKey: ...,
    authDomain: ...,
    projectId: ...,
    storageBucket: ...,
    messagingSenderId: ...,
    appId: ...
};
firebase.initializeApp(firebaseConfig);
export const auth = firebase.auth();
export const firestore = firebase.firestore();
export const firebaseObserver = ReactObserver();

auth.onAuthStateChanged(function(user) {
    firebaseObserver.publish("authStateChanged", loggedIn())
});

export function loggedIn() {
    return !!auth.currentUser;
}

Simplified version;简化版; You can use a logged in condition to load data;您可以使用登录条件来加载数据;

  /**
  * loggedIn = undefined when loading
  * loggedIn = true if loading is finished and there is a user
  * loggedIn = flase if loading is finished and there is no user
  */
  const [loggedIn, setLoggedIn] = useState<boolean>();
  auth.onAuthStateChanged((user) => {
    if (user) {
      setLoggedIn(true);
    } else {
      setLoggedIn(false);
    }
  });

  useEffect(() => {
    if (loggedIn != undefined) {
      //do loggedIn stuff
    }
  }, [loggedIn]);

To whom it may concern, adding a simple flag for when the authentication actually loaded solved the glitch for me.对于它可能关心的人来说,添加一个简单的标志来表示身份验证实际加载的时间为我解决了故障。 I also added protected routes (inspired by this article and I think I can continue on with my project nicely now.我还添加了受保护的路线(受这篇文章的启发,我想我现在可以继续我的项目了。

App.js : App.js

import {BrowserRouter, Redirect, Route, Switch} from "react-router-dom";
import Home from "./Home";
import Login from "./Login";
import {PrivateRoute} from "./PrivateRoute";
import {loggedIn, firebaseObserver} from "../firebase";
import {useEffect, useState} from "react";

export default function App() {
    const [authenticated, setAuthenticated] = useState(loggedIn());
    const [isLoading, setIsLoading] = useState(true);

    useEffect(() => {
        firebaseObserver.subscribe('authStateChanged', data => {
            setAuthenticated(data);
            setIsLoading(false);
        });
        return () => { firebaseObserver.unsubscribe('authStateChanged'); }
    }, []);

    return isLoading ? <div/> :
        <BrowserRouter>
            <Switch>
                <Route path="/" exact>
                    <Redirect to={authenticated ? "/home" : "/login"} />
                </Route>
                <PrivateRoute path="/home" exact
                              component={Home}
                              hasAccess={authenticated} />
                <PrivateRoute path="/login" exact
                              component={Login}
                              hasAccess={!authenticated} />
                <Route path="*">
                    <Redirect to={authenticated ? "/home" : "/login"} />
                </Route>
            </Switch>
        </BrowserRouter>;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM