reactjs - React 中的路由器、重定向和身份验证上下文问题
问题描述
我对 React 钩子还是新手,我正在尝试调整一些代码,以便仅在用户在 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;
我遇到的问题是,当我登录并且我在主页上时。如果我尝试将“/c”添加到 URL 以访问受保护的部分,我会被重定向回主页,就好像我没有登录一样。
当我登录时重新加载主页时,我得到 2 个控制台日志,一个说我没有登录,一个说我已经登录。而且我认为正在发生的事情是,在应用程序有机会呈现并看到我已登录之前,我被重定向了。这似乎得到了这样一个事实的证实,即如果我注释掉我的重定向,我可以到达/c
. 但是我没有得到该重定向的其他好处。
我难以理解的是为什么user.loggedIn
第一次渲染组件时是错误的。
解决方案
通过使用这个第三方库,我想出了如何在不重新发明轮子的情况下(并且不使用依赖于疯狂的实验性 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 的钩子完成初始化。
推荐阅读
- javascript - 为什么 if 条件中的代码即使不应该使用 react 和 javascript 也会执行?
- r - 将R中的表格按升序合并在一行中
- npm - 如何弃用发布到 GitHub 包注册表的 npm 包?
- android - Xamarin.Forms Tapped 事件,没有可绑定的属性
- nsis - NSIS 教程中的安装程序写入错误用户的桌面
- scala - Lagom Framework 手动 kafka 连接没有 kubernetes
- javascript - 更改字符串中的某些单词以突出显示(PHP)
- c# - 通过对象过滤时在 asp.net mvc 中保持模型状态
- javascript - Razorpay 结帐窗口未在 WordPress 中打开
- r - 具有多个组的ggplot2密度和trim = TRUE:密度不会变为0?