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;