开发者问题收集

React Router 先渲染无效组件,然后渲染有效组件

2021-01-08
118

每当我进入路径(“/”)时,即使我已经登录,注册组件也会加载一次几秒钟,然后显示仪表板,重定向时也会发生同样的情况,请问如何解决它。

<Route
    exact
    path="/"
    render={() => {
        return loggedIn ? <Dashboard /> : <Signup />;
    }}
/>

<Route
    exact
    path="/resetPassword"
    render={() => {
        return loggedIn ? (
            <Redirect to="/" />
        ) : (
            <ResetPassword/>
        );
    }}
/>

我正在像这样设置 login


const cookieCheck = () => {
  const mt = Cookies.get("rt");
  if (mt === "" || mt === undefined) {
    if (loggedIn) {
      setLogin(false);
    }
  } else {
    if (!loggedIn) {
      setLoggedIn(true);
    }
  }
};

我的完整代码如下

import React, { Fragment, useState, useEffect, lazy, Suspense } from 'react';
import { Paper } from '@material-ui/core';
import Dashboard from './Components/Dashboard/Dashboard';
import LoadingPage from './Components/LoadingPage/main';
import ForgotPassword from './Components/ForgotPassword/Fp';
import Signup from './Components/Signup/Signup';
import Login from './Components/Login/Login';
import PageNotFound from './Components/404/Page.js';
import Activation from './Components/Activation/Activation';
import ResetPassword from './Components/ResetPassword/Reset';
import {
    BrowserRouter as Router,
    Route,
    Switch,
    Redirect,
} from 'react-router-dom';
import Cookies from 'js-cookie';

const App = () => {
    const [login, setLogin] = useState(false);

    const checkStatus = function () {
        const mt = Cookies.get('t');
        if (mt === '' || mt === undefined) {
            setLogin(false);
        } else {
            setLogin(true);
            // return true;
        }
    };

    useEffect(() => {
        const interval = setInterval(() => {
            cookieCheck();
        }, 1000);
        return () => clearInterval(interval);
    });

    const cookieCheck = async () => {
        const mt = await Cookies.get('rt');
        if (mt === '' || mt === undefined) {
            if (login) {
                setLogin(false);
            }
        } else {
            if (!login) {
                setLogin(true);
            }
        }
    };

    console.log(login);
    return (
        <Router>
            <Fragment>
                <Paper elevation={0}>
                    <Switch>
                        <Route
                            path="/forgotpassword"
                            exact
                            component={ForgotPassword}
                        />
                        <Route
                            exact
                            path="/login"
                            render={() => {
                                return login ? <Redirect to="/" /> : <Login />;
                            }}
                        />
                        <Route
                            exact
                            path="/signup"
                            render={() => {
                                if (login) {
                                    return <Redirect to="/" />;
                                } else {
                                    return <Signup />;
                                }
                            }}
                        />

                            <Route
                                exact
                                path="/"
                                render={() => {
                                    return login ? (
                                        <Dashboard />
                                    ) : (
                                        <LoadingPage />
                                    );
                                }}
                            />


                        <Route
                            exact
                            path="/resetPassword/:code/:uid"
                            render={() => {
                                return login ? (
                                    <Redirect to="/" />
                                ) : (
                                    ResetPassword
                                );
                            }}
                        />
                        <Route
                            exact
                            path="/activation/:code/:uid"
                            component={Activation}
                        />
                        <Route component={PageNotFound} />
                    </Switch>
                </Paper>
            </Fragment>
        </Router>
    );
};

export default App;
2个回答

您需要尝试类似这样的操作来将 loading 状态添加到您的组件:

import React, { Fragment, useState, useEffect, lazy, Suspense } from "react";
import { Paper } from "@material-ui/core";
import Dashboard from "./Components/Dashboard/Dashboard";
import LoadingPage from "./Components/LoadingPage/main";
import ForgotPassword from "./Components/ForgotPassword/Fp";
import Signup from "./Components/Signup/Signup";
import Login from "./Components/Login/Login";
import PageNotFound from "./Components/404/Page.js";
import Activation from "./Components/Activation/Activation";
import ResetPassword from "./Components/ResetPassword/Reset";
import {
  BrowserRouter as Router,
  Route,
  Switch,
  Redirect,
} from "react-router-dom";
import Cookies from "js-cookie";

const App = () => {
  const [login, setLogin] = useState(false);
  const [loading, setLoading] = useState(true);

  const checkStatus = function () {
    const mt = Cookies.get("t");
    if (mt === "" || mt === undefined) {
      setLogin(false);
    } else {
      setLogin(true);
    }
    setLoading(false);
  };

  useEffect(() => {
    const interval = setInterval(() => {
      checkStatus();
    }, 1000);
    return () => clearInterval(interval);
  }, []);

  console.log(login);
  const isLoginComponent = login ? <Dashboard /> : <LoadingPage />;
  return (
    <Router>
      <Fragment>
        <Paper elevation={0}>
          <Switch>
            <Route path="/forgotpassword" exact component={ForgotPassword} />
            <Route
              exact
              path="/login"
              render={() => {
                return login ? <Redirect to="/" /> : <Login />;
              }}
            />
            <Route
              exact
              path="/signup"
              render={() => {
                if (login) {
                  return <Redirect to="/" />;
                } else {
                  return <Signup />;
                }
              }}
            />

            <Route
              exact
              path="/"
              render={() => {
                return loading ? <div>loading</div> : isLoginComponent;
              }}
            />

            <Route
              exact
              path="/resetPassword/:code/:uid"
              render={() => {
                return login ? <Redirect to="/" /> : ResetPassword;
              }}
            />
            <Route exact path="/activation/:code/:uid" component={Activation} />
            <Route component={PageNotFound} />
          </Switch>
        </Paper>
      </Fragment>
    </Router>
  );
};

export default App;

在此处阅读有关 cookies 如何工作的更多信息: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/cookies/get

Taghi Khavari
2021-01-08

我认为这个问题是您在组件安装时没有立即检查 cookie 状态。这与 login 初始状态 false 相结合,将呈现任何 login ? true : false false 分支组件,直到第一个 cookie 检查返回有效的身份验证。

const [login, setLogin] = useState(false);

const checkStatus = function () {
    const mt = Cookies.get('t');
    if (mt === '' || mt === undefined) {
        setLogin(false);
    } else {
        setLogin(true);
    }
};

useEffect(() => {
    const interval = setInterval(() => {
        checkStatus(); // <-- not called for 1000ms
    }, 1000);
    return () => clearInterval(interval);
});

解决方案

还需要立即调用 cookie 检查功能。我建议也从非 true/false 状态值开始,这样您就知道初始检查何时完成。

const [login, setLogin] = useState(null);

const checkStatus = function () {
    const mt = Cookies.get('t');
    if (mt === '' || mt === undefined) {
        setLogin(false);
    } else {
        setLogin(true);
    }
};

useEffect(() => {
    const interval = setInterval(() => {
        checkStatus();
    }, 1000);
    checkStatus(); // <-- also invoke first render
    return () => clearInterval(interval);
});

检查 login === null 并返回 null( 或任何待处理/加载的 UI 真的 ),否则返回常规三元组。

<Route
  exact
  path="/"
  render={() => {
    if (login === null) return null;
    return login ? (
      <Dashboard />
    ) : (
      <LoadingPage />
    );
  }}
/>
Drew Reese
2021-01-08