在 React 中单击导航栏 header 上的注销按钮后如何重定向到登录页面?

How to redirect to log in page after click logout button on navbar header in React?

我是 React 新手。我在 App.js 中有这样的 React 路由器配置:

<BrowserRouter>
    <div className="App">
      <Header />
      <Switch>
        <Route exact path="/" component={Home}>
        </Route>
        <Route exact path="/management" component={Management}>
        </Route>
        <Route exact path="/sign-up" component={SignUpForm}>
        </Route>
        <Route exact path="/sign-in" component={SignInForm}>
        </Route>
        <Route component={Error}>
        </Route>
      </Switch>
    </div>
  </BrowserRouter >

我想让header显示在每个页面,在header有一个注销按钮,我想在点击它后重定向到/sign-in页面。在我的 header 组件中是这样的:

class Header extends Component {
constructor(props) {
    super(props);
    this.state = {
        redirect: false
    }

}
logout = () => {
    sessionStorage.setItem("userToken", '');
    sessionStorage.clear();
    this.setState({ redirect: true });


}
render() {
    if (this.state.redirect) {
        return (
            <Redirect to={'/sign-in'} />
        )
    }


    return (
        <div>

            <Navbar collapseOnSelect expand="md" bg="dark" variant="dark" fixed="top" >
               ......
                        <NavLink to="/management" className="header-link"><FontAwesomeIcon icon="cog" size="lg" /></NavLink>
                        <button type='button' onClick={this.logout}>Log Out</button>
                    </Nav>
                </Navbar.Collapse>
            </Navbar>
        </div>
    );
}
}
export default Header;

会出现错误"Warning: You tried to redirect to the same route you're currently on: "/sign-in",导航栏会消失,只有sign-in的body显示。请问什么是正确的怎么做?我也试过 this.props.history.push('/sign-in') 但没有 props.history,可能是因为 header 不在路由中?我应该与路由器一起使用吗?或者我应该让每个页面都导入 header 而不是把它放在 app.js 中?或者实际上正确的方法是什么?非常感谢您的帮助!

您在这里提到了两种方法。您可以使用将传递给您的组件的高阶组件 'withRouter' that gives components access to the history object. By using the history 对象作为道具,您可以推送到您想要的路线。

就我个人而言,我喜欢设置注销 links 来呈现一个包含注销逻辑的组件,并在完成后呈现重定向到登录。这样,用户可以根据需要直接进入注销 link,并且您可以根据需要从应用中的任何位置 link 进入,而无需重复逻辑。

在您的浏览器路由器中,您可以为“/logout”添加一个路径来呈现这样的组件(根据您的逻辑):

import React, { Component } from 'react';
import { Redirect } from 'react-router';

export default class LogOut extends Component {
    state = {
        redirect: false,
    };

    componentDidMount() {
        sessionStorage.setItem("userToken", '');
        sessionStorage.clear();
        this.setState({ redirect: true });
    }

    render() {
        return this.state.redirect ?
            <Redirect to={'/sign-in'} /> :
            null;
    }
}

通常我会发出 ajax 请求来清除会话,然后在完成后设置状态,但你的都是服务器端的。

绑定到路由的组件可以访问历史对象作为道具,因此您可以根据需要更改它,例如注销。由于您的 Header 组件无法访问 history 对象,您将不得不使用较低级别的路由器来授予它访问 history 对象的权限:

import { Router } from "react-router"
import { createBrowserHistory } from "history"

const history = createBrowserHistory()

<Router history={history}>
  <div className="App">
      <Header history={history} />
      <Switch>
        <Route exact path="/" component={Home}>
        </Route>
        <Route exact path="/management" component={Management}>
        </Route>
        <Route exact path="/sign-up" component={SignUpForm}>
        </Route>
        <Route exact path="/sign-in" component={SignInForm}>
        </Route>
        <Route component={Error}>
        </Route>
      </Switch>
    </div>
</Router>

现在您可以在 Header 组件中调用 history.push('/login')

参见参考文献:https://reacttraining.com/react-router/web/api/Router/history-object

您可以通过使用 HOC 的路由实现 login/logout,HOC 会在每次路由更改时检查会话项。如果会话有 userToken 那么它将重定向到给定的组件,否则将重定向到登录组件。

import React from "react"
import {Redirect} from "react-router-dom"

export const PrivateRoute = ({component: Component, ...rest}) => (
    <Route {...rest} render={(props) => (
        sessionStorage.getItem('userToken') ? <Component {...props} /> : <Redirect to="/sign-in"/>
    )} />
)

导入<PrivateRoute>并将其用作授权路径。并将所有其他路径保留为您不需要授权的正常路径。

<BrowserRouter>
    <div className="App">
        <Header />
        <Switch>
            <PrivateRoute path="/" component={Home} />
            <PrivateRoute path="/management" component={Management} />
            <Route path="/sign-up" component={SignUpForm} />
            <Route path="/sign-in" component={SignInForm} />
            <Route component={Error} />
        </Switch>
    </div>
</BrowserRouter >

因此当您注销时,会话项目将被删除并自动重定向到登录页面。

class Header extends Component {

....

logout = () => {
    sessionStorage.removeItem("userToken");
    sessionStorage.clear(); 
}

render() {
    return (
        <div>
          ...
          <button type='button' onClick={this.logout}>Log Out</button>
        </div>
    )
}
}
export default Header;