Home > Back-end >  Invalid Hook Call - Works in single React.js file, not in 2 ReactJS files
Invalid Hook Call - Works in single React.js file, not in 2 ReactJS files

Time:01-17

I am trying to make a logout button work in a Navbar in my ReactJS app.

I have the following functionality in App.tsx:

import Navbar from './Navbar';

function App() {
  const [provider, setProvider] = useState<SafeEventEmitterProvider | null>(
    null
  );



  const logout = async () => {
    await authlibrary.logout();
    setProvider(null);
  };

const loggedInView = (
    <>
       <div className="App">
       <button onClick={logout} className="card">
        Log Out
       </button>
       <Navbar /> 
       <BrowserRouter>
        <div className="Content">
          <Routes>
            <Route path="/" element={<Home />}>
            </Route>
            <Route path="/other" element={<OtherRoute />}>
            </Route>
          </Routes>
        </div>
      </BrowserRouter>
      <Footer />
      </div>
    </>
  );

  const mql = window.matchMedia('(max-width: 576px)');

let mobileView = mql.matches;
  if (mobileView) {
  return (
    <div className="container">
      <div className="grid">{provider ? loggedInView : unloggedInView}</div>
    </div>
  );
 }
}
export default App;

In the above example the button works as intended, however, I wish to now place it on my Navbar, which is in a separate file Navbar.tsx as follows:

import logout from './App';

const Navbar = () => {
    return ( 
        
        <nav className="nav sidebar">
            <a href="/home" className="nav__link">Home</a>
            <a href="/other" className="nav__link">Other Stuff</a>
            <button onClick={logout} className="nav__link" id="btn-logout">Log Out</button>
            
        </nav>
     );
}
 
export default Navbar;

When I click on the button in Navbar.tsx above, I get the following error in the console log:

Error: Invalid hook call. Hooks can only be called inside of the body of a function component.

I understand that I am misusing hooks to get the error message, however, I cannot figure out how to correctly use the hook in the second Navbar.tsx file?

CodePudding user response:

To correctly use the logout hook in the Navbar.tsx file, I need to pass the logout function as a prop to the Navbar component, and then call the function when the logout button is clicked. Here's an example of how you can do this:

In App.tsx:

const logout = async () => {
    await web3auth.logout();
  };

return (
    <BrowserRouter>
        <Navbar logout={logout} />
        <Routes>
            {/* Add your routes here */}
        </Routes>
    </BrowserRouter>
)

In Navbar.tsx:

interface Props {
    logout: () => void;
}

const Navbar: React.FC<Props> = ({ logout }) => {
    return (
        <nav>
            {/* Other navbar code */}
            <button onClick={logout}>Logout</button>
        </nav>
    );
};

export default Navbar;

You need to ensure that the logout function is called after the user has been authenticated, or the user may not be able to logout.

CodePudding user response:

In your Navbar component, you are trying to import the logout function from the App component and use it as a hook. However, hooks can only be used inside the body of a function component and not in other components or regular JavaScript files. To solve this issue, you can pass the logout function as a prop to the Navbar component and use it in the onClick event of the logout button.

In App.tsx:

const loggedInView = ( <> <Navbar logout={logout} /> <BrowserRouter>
  <div className="Content">
    <Routes>
      <Route path="/" element={<Home />}>
      </Route>
      <Route path="/other" element={<OtherRoute />}>
      </Route>
    </Routes>
  </div>
</BrowserRouter>
<Footer /> </> );

In Navbar.tsx:

interface Props { logout: () => void } const Navbar: React.FC<Props> = ({ logout }) => { return (
<nav className="nav sidebar">
  <a href="/home" className="nav__link">Home</a>
  <a href="/other" className="nav__link">Other Stuff</a>
  <button onClick={logout} className="nav__link" id="btn-logout">Log Out</button>
</nav> ); } export default Navbar;
  • Related