React中路由器,重定向和身份验证上下文的问题

时间:2020-05-11 11:28:31

标签: reactjs firebase firebase-authentication react-router react-hooks

我仍然对React钩子不熟悉,并且我尝试修改some code以仅允许在Firebase中对用户进行身份验证的情况下访问某些路由。同时,我希望用户键入不存在的路径,将其重定向到首页。而且,如果他在注销时尝试访问其中一条受保护的路由,则还应该将其重定向到家庭。这是我的App.js的样子:

import React, {Fragment, lazy, Suspense, useState, useEffect} from "react";
import {CssBaseline, MuiThemeProvider} from "@material-ui/core";
import {BrowserRouter, Redirect, Route, Switch} from "react-router-dom";
import theme from "./theme";
import GlobalStyles from "./GlobalStyles";
import * as serviceWorker from "./serviceWorker";
import Pace from "./shared/components/Pace";
import Firebase from "./firebase";
import FirebaseContext from "./firebase-context";

const firebase = new Firebase();

const LoggedInComponent = lazy(() => import("./logged_in/components/Main"));

const LoggedOutComponent = lazy(() => import("./logged_out/components/Main"));

function onAuthStateChange(callback) {
    return firebase.auth.onAuthStateChanged(user => {
        if(user) {
            callback({loggedIn: true});
        } else {
            callback({loggedIn: false});
        }
    });
}

function App() {
    const [user, setUser] = useState({loggedIn: false});

    useEffect(() => {
        const unsubscribe = onAuthStateChange(setUser);
        return () => {
            unsubscribe();
        }
    }, [setUser]);
    console.log("logged in?", user.loggedIn);

    return (
        <BrowserRouter>
            <FirebaseContext.Provider value={firebase}>
                <MuiThemeProvider theme={theme}>
                    <CssBaseline/>
                    <GlobalStyles/>
                    <Pace color={theme.palette.primary.light}/>
                    <Suspense fallback={<Fragment/>}>
                        <Switch>
                            {user.loggedIn && <Route path="/c" component={LoggedInComponent}/>}
                            <Route exact path="/" component={LoggedOutComponent}/>
                            <Redirect to="/"/>
                        </Switch>
                    </Suspense>
                </MuiThemeProvider>
            </FirebaseContext.Provider>
        </BrowserRouter>
    );
}

serviceWorker.register();

export default App;

我遇到的问题是,当我登录并进入主页时。如果我尝试在URL中添加“ / c”以获取受保护的部分,则会被重定向回主页,就像我没有登录一样。

当我登录后重新加载主页时,会收到2条控制台日志,其中一条说我没有登录,另一条说我是。而且我认为发生了什么事,就是在应用程序有机会呈现并看到我已登录之前,我已被重定向。这似乎可以由以下事实证实:如果我注释掉我的重定向,我可以进入{{ 1}}。但是后来我没有获得该重定向的其他好处。

我很难理解的是为什么/c第一次呈现组件时为假。

1 个答案:

答案 0 :(得分:0)

我想出了如何使用this third party library而不重新发明轮子(也不需要使用依赖疯狂的实验性React东西的ReactFire)来做到这一点。这是结果代码:

import React, { Fragment, Suspense, lazy, useContext } from "react";
import { MuiThemeProvider, CssBaseline } from "@material-ui/core";
import { Route, Switch, Redirect } from "react-router-dom";
import theme from "./theme";
import GlobalStyles from "./GlobalStyles";
import * as serviceWorker from "./serviceWorker";
import Pace from "./shared/components/Pace";
import {useAuthState} from "react-firebase-hooks/auth";
import FirebaseContext from "./firebase-context";
import LinearProgress from "@material-ui/core/LinearProgress";

const LoggedInComponent = lazy(() => import("./logged_in/components/Main"));

const LoggedOutComponent = lazy(() => import("./logged_out/components/Main"));

function App() {
  const firebase = useContext(FirebaseContext);
  const [user, initialising, error] = useAuthState(firebase.auth);
  console.log("user", user);
  console.log("initialising", initialising);
  console.log("error", error);
  return (
      <MuiThemeProvider theme={theme}>
        <CssBaseline />
        <GlobalStyles />
        <Pace color={theme.palette.primary.light} />
        {initialising ? <LinearProgress/> :
        <Suspense fallback={<Fragment />}>
          <Switch>
            {user && <Route path="/c">
              <LoggedInComponent />
            </Route>}
            <Route exact path="/">
              <LoggedOutComponent />
            </Route>
            <Redirect to="/"/>
          </Switch>
        </Suspense>}
      </MuiThemeProvider>
  );
}

serviceWorker.register();

export default App;

实际上,我必须延迟路由选择开关的显示,直到Firebase auth的钩子完成初始化为止。