简体   繁体   中英

history.push to /login (on logout) is not working in react-router-dom

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?

Try using:

import { useHistory } from "react-router-dom";

const history = useHistory();

const logoutSubmitHandler = () => {
  history.push("/login");
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM