0

I have my navigation component here:

import 'navigations/NavMenu.scss';
import React, { Component } from 'react';
import { Collapse, Container, Navbar, NavbarBrand, NavbarToggler, NavItem, NavLink } from 'reactstrap';
import { Link } from 'react-router-dom';
import { useHistory } from 'react-router-dom';
import { Util } from 'helpers/Util';

export class NavMenu extends Component {
    static displayName = NavMenu.name;

    constructor(props) {
        super(props);

        this.toggleNavbar = this.toggleNavbar.bind(this);
        this.closeNavbar = this.closeNavbar.bind(this);
        this.logout = this.logout.bind(this);
        this.state = {
            collapsed: true
        };
    }

    toggleNavbar() {
        this.setState({
            collapsed: !this.state.collapsed
        });
    }

    closeNavbar() {
        if (!this.state.collapsed)
            this.setState({ collapsed: true });
    }

    async logout() {
        const history = useHistory();
        let success = await Util.logout();
        if (success) {
            history.push('/login?msg=' + encodeURI('Success! You have been logged-out.') + '&type=success');
        }
        this.closeNavbar();
    }

    render() {
        let theme = localStorage.getItem('theme');
        let navbarClass = "navbar navbar-expand-sm navbar-toggleable-sm ng-white border-bottom box-shadow mb-3";
        let login = Util.isUserLoggedIn() ?
            <NavLink onClick={this.logout} tag={Link} className={theme == 'dark' ? 'text-light' : 'text-dark'} to="/login">Logout</NavLink> :
            <NavLink onClick={this.closeNavbar} tag={Link} className={theme == 'dark' ? 'text-light' : 'text-dark'} to="/login">Login</NavLink>

        return (
            <header>
                <nav className={theme == 'dark' ? navbarClass + ' navbar-dark' : navbarClass + 'navbar-light'}>
                    <Container>
                        <NavbarBrand tag={Link} to="/">NetCoreReact</NavbarBrand>
                        <NavbarToggler onClick={this.toggleNavbar} className="mr-2" />
                        <Collapse className="d-sm-inline-flex flex-sm-row-reverse" isOpen={!this.state.collapsed} navbar>
                            <ul className="navbar-nav flex-grow">
                                <NavItem>
                                    <NavLink onClick={this.closeNavbar} tag={Link} className={theme == 'dark' ? 'text-light' : 'text-dark'} to="/">Home</NavLink>
                                </NavItem>
                                <NavItem>
                                    <NavLink onClick={this.closeNavbar} tag={Link} className={theme == 'dark' ? 'text-light' : 'text-dark'} to="/counter">Counter</NavLink>
                                </NavItem>
                                <NavItem>
                                    <NavLink onClick={this.closeNavbar} tag={Link} className={theme == 'dark' ? 'text-light' : 'text-dark'} to="/fetch-data">Fetch data</NavLink>
                                </NavItem>
                                <NavItem>
                                    {login}
                                </NavItem>
                            </ul>
                        </Collapse>
                    </Container>
                </nav>
            </header>
        );
    }
}

I want to logout() by pressing logout navigation link. But the useHistory() messes me up here. This is the error:

Unhandled Rejection (Error): Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:

  1. You might have mismatching versions of React and the renderer (such as React DOM)
  2. You might be breaking the Rules of Hooks
  3. You might have more than one copy of React in the same app See .... for tips about how to debug and fix this problem.

When this code is called:

history.push('/login?msg=' + encodeURI('Success! You have been logged-out.') + '&type=success');

How can I safely navigate?

Håken Lid
  • 22,318
  • 9
  • 52
  • 67
Alvin Stefanus
  • 1,873
  • 2
  • 22
  • 60
  • 2
    Hooks cannot be used in `Class` based components you have to change this component to `functional` component if you want to use `React Hooks` Or you can `import { withRouter } from 'react-router-dom'` and wrap `NavMenu` with `withRouter` HOC and get access to history via props ie `props.history` – Sayog Feb 26 '21 at 07:08
  • There are many questions about using history in react router components. However, the approach depends on which version of react router you are using. For the latest version of react router, it seems they only want you to use function components. – Håken Lid Mar 19 '21 at 08:18
  • https://stackoverflow.com/questions/59402649/how-can-i-use-history-pushpath-in-react-router-5-1-2-in-stateful-component – Håken Lid Mar 19 '21 at 08:19

1 Answers1

0

This is not a direct solution however just want to share this approach. I was facing similar kind of issue in approaching a login and logout. I followed this approach and it works for me. I have used 'react-bootstrap' unlike 'reactstrap' in your code

ReactJS Bootstrap Navbar and Routing not working together

and you can use Redirect from 'react-router-dom'

import { Redirect, Route, Switch, Link } from "react-router-dom"

and use the Redirect in render method of the logout component like I did for Login component (I am redirecting to home based on a state of the component),

<Route path='/login' 
exact
render = {()=>(this.state.bLoggedIn ? <Redirect to="/home" /> :  
<>
<Login usr={this.getActiveUser}/>
</>
)}
/>
AspireToLearn
  • 21
  • 1
  • 3