history.push 到/login(注销时)在 react-router-dom 中不起作用 [英] history.push to /login (on logout) is not working in react-router-dom

查看:49
本文介绍了history.push 到/login(注销时)在 react-router-dom 中不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当用户使用他/她的凭据登录时,用户名会显示在 Header 组件上.用户可以使用 logout 链接注销.

当用户点击 logout 链接时,我会删除保存在本地存储中的 loggedInUser 对象.然后,我将用户引导至 /login 路由,在此向用户显示登录表单.

当我使用 history.push("/login") 并单击 logout 链接时,没有任何反应.loggedInUser 对象不会从本地存储中删除,我也不会被定向到 login 路由.但是,如果我使用 window.location = "/login",一切都按预期工作.

为什么 hitory.push("/login") 没有按预期工作?

Header.js:

从反应"导入反应;import { Link, withRouter } from react-router-dom";import { useDispatch, useSelector } from react-redux";import { logout } from "./stateSlices/loginSlice";const Header = ({ history }) =>{const { loginUser } = useSelector((state) => state.login);const dispatch = useDispatch();const logoutSubmitHandler = () =>{调度(注销());localStorage.removeItem(loggedInUser");window.location =/登录";//这有效//history.push("/login");//这不起作用};返回 (<标题><导航><ul className="navbar-list">{登录用户?(<div className="下拉列表"><按钮className =btn btn-lg btn-primary dropdown-toggle"类型=按钮"id="dropdownMenu2";数据切换=下拉"aria-haspopup="true";aria-expanded="false";>{loggedInUser.firstName}

) : (<链接到=/登录"className=导航栏列表项">注册/登录</链接>)}</nav></标题>);};导出默认 withRouter(Header);

App.js:

从反应"导入反应;从./components/Header"导入头文件;import { Route, Switch } from react-router-dom";从./components/LoginForm"导入登录表单;从./components/RegisterForm"导入RegisterForm;import Welcome from "./components/Welcome";从./components/PasswordResetFormEmail"导入 PasswordResetFormEmail;从./components/PasswordResetFormPassword"导入 PasswordResetFormPassword;const App = () =>{返回 (<><标题/><开关><路线path="/password/reset/:token";组件={PasswordResetFormPassword}/><路线路径=/帐户/密码/忘记";组件={PasswordResetFormEmail}/><路由路径="/register";组件={RegisterForm}/><路由路径="/login";组件={登录表单}/><路由路径="/welcome";组件={欢迎}/></开关></>);};导出默认应用程序;

index.js:

从反应"导入反应;从react-dom"导入 ReactDOM;导入bootstrap/dist/css/bootstrap.min.css";导入./index.css";从./App"导入应用程序;从./reportWebVitals"导入reportWebVitals;import { BrowserRouter as Router } from react-router-dom";从react-redux"导入{提供者};从./store"导入商店;ReactDOM.render(<提供者商店={商店}><路由器><应用程序/></路由器></提供者>,document.getElementById("root"));

解决方案

你的 redux slice 中有一个错字:

reducers: {注销(状态,动作){//state.user = null;//<-- 打字错误state.loggedInUser = null;//这是正确的},},

但是,在修正错字后,我建议您重构代码并创建一个PrivateRoute";docs 中演示的组件:

const PrivateRoute = ({ children, ...rest }) =>{const { loginUser } = useSelector((state) => state.login);返回 (<路线{...休息}渲染={({位置})=>登录用户 ?(孩子们) : (<重定向到={{ pathname: "/login", state: { from: location } }}/>)}/>);};

并在所有私有路由的App组件中使用它:

<欢迎/></PrivateRoute>

现在,这样,PrivateRoute 将负责重定向"到登录页面,您需要做的就是清除"您的 redux 状态中的 loggedInUser.


请注意,最好使用儿童";定义路由时的表单.请参阅 在 React 中使用 react-router-dom 在 App.js 中配置路由的更好方法是什么?

When the users logs in using his/her credentials, the name of the user is displayed on the Header component. The user can log out using the logout link.

When the user clicks on the logout link, I remove the loggedInUser object saved in local storage. Then, I direct the user to the /login route, where I show the login form to the user.

When I use history.push("/login"), and click on the logout link, nothing happens. The loggedInUser object does not get removed from the local storage, and I am not directed to the login route. However, if I use window.location = "/login", everything works as expected.

Why is hitory.push("/login") not working as expected?

Header.js:

import React from "react";
import { Link, withRouter } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { logout } from "./stateSlices/loginSlice";

const Header = ({ history }) => {
  const { loggedInUser } = useSelector((state) => state.login);
  const dispatch = useDispatch();

  const logoutSubmitHandler = () => {
    dispatch(logout());
    localStorage.removeItem("loggedInUser");
    window.location = "/login"; // THIS works
    // history.push("/login"); // THIS does not work
  };

  return (
    <header>
      <nav>
        <ul className="navbar-list">
          {loggedInUser ? (
            <div className="dropdown">
              <button
                className="btn btn-lg btn-primary dropdown-toggle"
                type="button"
                id="dropdownMenu2"
                data-toggle="dropdown"
                aria-haspopup="true"
                aria-expanded="false"
              >
                {loggedInUser.firstName}
              </button>
              <div
                className="dropdown-menu dropdown-menu-right"
                aria-labelledby="dropdownMenu2"
              >
                <button
                  className="dropdown-item"
                  type="button"
                  onClick={logoutSubmitHandler}
                >
                  Logout
                </button>
              </div>
            </div>
          ) : (
            <Link to="/login" className="navbar-list-item">
              Register/Login
            </Link>
          )}
        </ul>
      </nav>
    </header>
  );
};

export default withRouter(Header);

App.js:

import React from "react";
import Header from "./components/Header";
import { Route, Switch } from "react-router-dom";
import LoginForm from "./components/LoginForm";
import RegisterForm from "./components/RegisterForm";
import Welcome from "./components/Welcome";
import PasswordResetFormEmail from "./components/PasswordResetFormEmail";
import PasswordResetFormPassword from "./components/PasswordResetFormPassword";

const App = () => {
  return (
    <>
      <Header />
      <Switch>
        <Route
          path="/password/reset/:token"
          component={PasswordResetFormPassword}
        />
        <Route
          path="/account/password/forgot"
          component={PasswordResetFormEmail}
        />
        <Route path="/register" component={RegisterForm} />
        <Route path="/login" component={LoginForm} />
        <Route path="/welcome" component={Welcome} />
      </Switch>
    </>
  );
};

export default App;

index.js:

import React from "react";
import ReactDOM from "react-dom";
import "bootstrap/dist/css/bootstrap.min.css";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { BrowserRouter as Router } from "react-router-dom";
import { Provider } from "react-redux";
import store from "./store";

ReactDOM.render(
  <Provider store={store}>
    <Router>
      <App />
    </Router>
  </Provider>,
  document.getElementById("root")
);

解决方案

You have a typo in your redux slice:

reducers: {
  logout(state, action) {
    // state.user = null; // <-- Typo error
    state.loggedInUser = null; // This is the correct one
  },
},

But, after fixing the typo, I would recommend that you refactor your code and create a "PrivateRoute" component as demoed in the docs:

const PrivateRoute = ({ children, ...rest }) => {
  const { loggedInUser } = useSelector((state) => state.login);
  return (
    <Route
      {...rest}
      render={({ location }) =>
        loggedInUser ? (
          children
        ) : (
          <Redirect to={{ pathname: "/login", state: { from: location } }} />
        )
      }
    />
  );
};

and use it in App component for all the private routes:

<PrivateRoute path="/welcome">
  <Welcome />
</PrivateRoute>

Now, this way, PrivateRoute will take care of "redirection" to the login page, all you need to do is "clear" the loggedInUser in your redux state.


Note that it is better to use "children" form when defining Routes. See What's the better way to configure routes in App.js in React with react-router-dom?

这篇关于history.push 到/login(注销时)在 react-router-dom 中不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆