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

1tu0hz3e  于 2022-12-04  发布在  React
关注(0)|答案(2)|浏览(121)

我正在开发一个集成了Firebase的React web应用程序,我正在尝试对我的用户进行身份验证。我已经设置了路径,如果用户通过身份验证,则显示Home组件,否则显示Login页面。但是当我的应用程序首次加载时,它会显示Login页面,并花一两秒钟的时间来识别用户实际上已通过身份验证,然后切换到Home页面。这看起来很混乱,我猜我处理onAuthStateChanged不够好或者不够快。在我的App组件中,我订阅了一个ReactObserver,它在auth状态改变时发出信号。我该怎么做才能避免这种奇怪的行为呢?
我的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>;
}

我的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;
}
wz8daaqr

wz8daaqr1#

对于它可能关心的人,添加一个简单的标志,当身份验证实际加载解决了我的小故障。我还添加了受保护的路由(受this article的启发,我认为我可以继续我的项目很好了。
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>;
}
5t7ly7z5

5t7ly7z52#

简化版;您可以使用登录条件加载数据;

/**
  * 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]);

相关问题