【问题标题】:Issue with Router, Redirect and authentication context in ReactReact 中的路由器、重定向和身份验证上下文问题
【发布时间】:2020-08-26 22:20:46
【问题描述】:

我还是 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 个控制台日志,一个说我没有登录,一个说我已经登录。而且我认为正在发生的事情是,在应用程序有机会渲染并看到我已登录之前,我被重定向了。这似乎可以通过以下事实得到证实,如果我注释掉我的重定向,我可以到达 @987654323 @。但是我没有得到该重定向的其他好处。

我难以理解的是为什么user.loggedIn 在第一次渲染组件时为假。

【问题讨论】:

  • “我难以理解的是为什么 user.loggedIn 在组件第一次渲染时为假。” - 因为您在 useState() 中将其设置为 false 作为初始值
  • 好的,我明白了。但是,当然,如果我将初始状态loginIn 设置为true,并且我在注销时尝试加载受保护的路由,则在重定向到主页之前允许短暂的时间,所以看起来很冒险。那里的解决方案是什么?
  • 可以初始化为null。所以现在你知道它是否为空,那么网络请求仍在继续,所以你可以加载微调器或其他东西。然后您可以使用从后端获得的数据更改状态

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


【解决方案1】:

通过使用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 的钩子完成初始化。

【讨论】:

    猜你喜欢
    • 2021-08-09
    • 2016-12-11
    • 2018-05-16
    • 1970-01-01
    • 2020-06-11
    • 2015-11-30
    • 2016-09-01
    • 2021-12-20
    • 2019-01-25
    相关资源
    最近更新 更多