簡體   English   中英

React 路由器會短暫顯示登錄屏幕,然后如果用戶已登錄,則會重定向到儀表板

[英]React router briefly shows the login screen and then redirects to dashboard if user is logged in

我有一個登錄頁面、一個儀表板頁面以及其他一些頁面。 我使用 firebase 作為后端。 我在登錄組件上執行了條件渲染,以檢查用戶是否登錄。 (如果已登錄,則會重定向到儀表板)。 如果用戶未登錄,我已將ProtectedRoutes用於儀表板和其他人以重定向到登錄頁面。

發生的情況是,當我在登錄為真時重新加載儀表板頁面或任何其他頁面時,我簡要地看到了登錄組件,然后它執行 firebase“ auth.onAuthStateChanged ”方法並將登錄的 state 設置為真並將我重定向回來到儀表板。 我確實理解為什么我會簡要地看到登錄頁面,但我不知道如何解決這個問題。

 import React, { useState } from 'react' import { connect } from "react-redux" import { signin, autoSignin } from "../Redux/Actions/AuthActions" import { Redirect } from 'react-router-dom' const Login = (props) => { const [form, setForm] = useState({}) const [disable, setDisable] = useState(false) const handleChange = (e) => { setForm({...form, [e.target.name]: e.target.value }) } const handleSubmit = (e) => { setDisable(true) e.preventDefault() props.signin(form.email, form.password) setDisable(false) } return ( props.auth.loggedin? <Redirect to="/dashboard" />: <div className="container-fluid login_screen"> <div className="row justify-content-center"> <div className="col-md-4 col-xs-12"> <img className="img-fluid login_screen_logo mt-4" src="/images/logo.png" alt="logo" /> <h1 className="mt-4 fs-3 heading">LOGIN</h1> <p className="fs-6 mb-3">to access dashboard</p> <form onSubmit={handleSubmit}> <div className="form-floating mb-4 mt-4"> <input name="email" onChange={handleChange} required type="email" className="form-control shadow-sm" id="floatingInput" placeholder="room@adil.tower" /> <label htmlFor="floatingInput">Email id</label> </div> <div className="form-floating mt-4"> <input name="password" onChange={handleChange} required type="password" className="form-control shadow-sm" id="floatingPassword" placeholder="Password" /> <label htmlFor="floatingPassword">Password</label> </div> <div className="d-grid gap-2"> <button type="submit" className={`btn btn-custom mt-4 btn-lg shadow ${disable? "disabled": ""}`}>LOGIN</button> </div> </form> </div> </div> </div> ) } const mapStateToProps = (state) => { return { auth: state.auth } } const mapDispatchToProps = (dispatch) => { return { signin: (email, pass) => dispatch(signin(email, pass)), autoSignin: (uid) => dispatch(autoSignin(uid)) } } export default connect(mapStateToProps, mapDispatchToProps)(Login)

 import React from 'react' const Dashboard = (props) => { return ( <h1> dashboard </h1> ) } export default Dashboard

 import React from 'react' import { Redirect, Route } from "react-router-dom" const ProtectedRoute = ({ loggedin, component: Component, ...rest }) => { return ( <Route {...rest} render={ (props) => { if (loggedin) { return <Component {...props} /> } else { return <Redirect to="/" /> } } } /> ) } export default ProtectedRoute

 import React, { useEffect } from 'react' import { BrowserRouter as Router, Switch, Route } from "react-router-dom" import ProtectedRoute from './ProtectedRoute' import { auth } from "./FirebaseConfig" // SCREENS import Dashboard from './Dashboard/Dashboard' import Login from "./Login/Login" import Profile from './Profile/Profile' import Emergency from './Emergency/Emergency' import Notice from './Notice/Notice' import Complains from "./Complains/Complains" import Meetings from "./Meetings/Meetings" // REDUX STORE & ACTIONS import { connect } from "react-redux" import { autoSignin } from "./Redux/Actions/AuthActions" const App = (props) => { useEffect( () => { auth.onAuthStateChanged(user => { if (user) { props.autoSignin(user.uid) } }) }, [] ) return ( <Router> <Switch> <ProtectedRoute loggedin={props.auth.loggedin} exact path="/dashboard" component={Dashboard}></ProtectedRoute> <Route exact path="/"><Login /></Route> <ProtectedRoute loggedin={props.auth.loggedin} exact path="/profile" component={Profile}></ProtectedRoute> <ProtectedRoute loggedin={props.auth.loggedin} exact path="/emergency" component={Emergency}></ProtectedRoute> <ProtectedRoute loggedin={props.auth.loggedin} exact path="/notices" component={Notice}></ProtectedRoute> <ProtectedRoute loggedin={props.auth.loggedin} exact path="/complains" component={Complains}><Complains /> </ProtectedRoute> <ProtectedRoute loggedin={props.auth.loggedin} exact path="/meetings" component={Meetings} ></ProtectedRoute> </Switch> </Router> ) } const mapStateToProps = (state) => { return { auth: state.auth } } const mapDispatchToProps = (dispatch) => { return { autoSignin: (uid) => dispatch(autoSignin(uid)) } } export default connect(mapStateToProps, mapDispatchToProps)(App)

我不會編輯您的代碼,只解釋基本原理:在渲染受保護的路線期間,您有 2 個選項:

要么等到身份驗證解決(props.auth.loggedin 為真或假,但不是未定義 - 假設您從 BE 收到這些值)。 同時,顯示加載屏幕。 解決此問題后,您將顯示您的頁面,或重定向到登錄。

第二種選擇是僅向前 go 並開始渲染私有(受保護)路由。 用戶將看不到任何私人數據,因為這些數據來自后端,並且這些后端調用也受到后端身份驗證的保護。 這種方法將允許您直接開始渲染受保護路由的內容,同時等待 props.auth.loggedin 從后端到達 - 在您的 App 組件中,設置 React.useEffect 監聽 props.auth.loggedin . 如果用戶未通過身份驗證,則將他重定向到登錄頁面。 如果他是,則沒有任何變化(或者您也可以讓您的 state 管理層也知道這一點)。

為了您的靈感,我在代碼中包含了我是如何做到的:

export const AppRoute: React.FC<RouteProps> = observer((props: RouteProps) => {
const { user } = useMst();
const { component, ...rest } = props;
if (!user.isAuthenticated) {
  return <Redirect to={"/login"} />;
}

const Component = component as any;

return (
  <Route
    {...rest}
    render={(props) => (
      <Layout>
        <Component {...props} />
      </Layout>
    )}
  />
);
});

然而,在這段代碼中,我存儲了有關用戶是否在 Mobex 中經過身份驗證的信息,並監聽 Mobex state 的變化 - 所以當 Mobex 意識到用戶未經過身份驗證時,它將觸發該重定向語句的執行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM