Home > OS >  Why can't I call a React hook from this functional component?
Why can't I call a React hook from this functional component?

Time:12-14

I'm trying to implement a navigation bar with the logout option.

Here's the code for my functional component:

import React, { useState } from 'react';
import { Nav, NavDropdown } from 'react-bootstrap';
import { useSelector, useDispatch } from 'react-redux';
import { useNavigate } from 'react-router-dom';

function MainMenu(props) {
    const user = useSelector(state => state.user);
    const dispatch = useDispatch();
    const navigate = useNavigate();
    
    const handleLogout = () => {
        dispatch({
            type: 'user/logout'            
        });
        navigate('/home');
    };

    const logedInMenu = (<NavDropdown title={user.name} id="basic-nav-dropdown">
        <NavDropdown.Item href="/dashboard">Dashboard</NavDropdown.Item>
        <NavDropdown.Item href="/upload">Upload new Meme</NavDropdown.Item>
        <NavDropdown.Divider />
        <NavDropdown.Item href="#" onClick={handleLogout}>Logout</NavDropdown.Item>
    </NavDropdown>);

    const publicMenu = (<Nav className='me-auto'>
        <Nav.Link href="/login">Login</Nav.Link>
        <Nav.Link href="/signup">Signup</Nav.Link>
    </Nav>);

    return (user ? logedInMenu : publicMenu);
}

export default MainMenu;

The problem I have is that when I try to use this component:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import 'bootstrap/dist/css/bootstrap.min.css';
import { BrowserRouter, Routes, Route, Navigate, useNavigate } from 'react-router-dom'
import Home from './Home';
import About from './About';
import Contact from './Contact';
import Login from './Login';
import Signup from './Signup';
import Dashboard from './Dashboard';
import Upload from './Upload';
import { getUser, removeUserSession } from './Utils/Common';
import MainMenu from './MainMenu';
import { Navbar, Container, Nav } from 'react-bootstrap';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
const mainMenu = MainMenu();
const user = getUser();

const userReducer = (state, action) => {
    switch (action.type) {
        case 'user/login':
            return {
                user: action.payload.user,
                token: action.payload.token
            }
        case 'user/logout':
            return {
                user: null,
                token: null
            }
        default:
            return {
                user: null,
                token: null
            }
    }
};

let store = createStore(userReducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
const routing = (
    <Provider store={store}>
        <Navbar bg="light" expand="lg">
            <Container>
                <Navbar.Brand href="#home">Leeway Academy</Navbar.Brand>
                <Navbar.Toggle aria-controls="basic-navbar-nav" />
                <Navbar.Collapse id="basic-navbar-nav">
                    <Nav className="me-auto">
                        <Nav.Link href="/">Home</Nav.Link>
                        {mainMenu}
                    </Nav>
                </Navbar.Collapse>
            </Container>
        </Navbar>
        <BrowserRouter>
            <div>
                <Routes>
                    <Route path="/" element={<Home />} />
                    <Route path="/about" element={<About />} />
                    <Route path="/contact" element={<Contact />} />
                    <Route path="/login" element={<Login />} />
                    <Route path="/signup" element={<Signup />} />
                    <Route path="/dashboard" element={
                        <RequireAuth redirectTo="/login">
                            <Dashboard />
                        </RequireAuth>
                    } />
                    <Route path="/upload" element={
                        <RequireAuth redirectTo="/login">
                            <Upload />
                        </RequireAuth>
                    } />
                </Routes>
            </div>
        </BrowserRouter>
    </Provider>
)

function RequireAuth({ children, redirectTo }) {
    return getUser() ? children : <Navigate to={redirectTo} />;
}

ReactDOM.render(routing, document.getElementById('root'));

I get this error:

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 https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.

I don't understand why this is happening. I put together the login component using a seemingly similar approach and didn't have any problem.

Could this mean React is not recognizing my function as a functional component?

CodePudding user response:

const mainMenu = MainMenu();

You're calling MainMenu as a regular function when the module loads, and not as a component inside the React tree.

You need to get rid of that and use <MainMenu /> where you have {mainMenu}

  • Related