Search code examples
reactjsreact-router-v4

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


I'm new to React. I have react router config in App.js like this:

<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 >

I want header to show in every page, there's a button of logout at header, I want to redirect to /sign-in page after I click it. In my header component it's like this:

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;

There will be errors "Warning: You tried to redirect to the same route you're currently on: "/sign-in", and the nav bar will disappear only the body of sign-in shows. May I know what is the correct way to do this? I also tried this.props.history.push('/sign-in') but there's no props.history, probably because header is not in route? Should i use with Router? Or should I actually just make every page import header instead put it in app.js? or what is actually the right way to do this? Thank you so much for your help!


Solution

  • You can implement login/logout with route using HOC that checks the session item with every route change. If the session has userToken then it will redirect to given component otherwise will redirect to login component.

    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"/>
        )} />
    )
    

    import <PrivateRoute> and use it as the authorized path. And keep all the other path as normal routes in which you don't want authorization.

    <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 >
    

    So while you do log out, the session item will be removed and automatically redirect to sign-in page.

    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;