I would like to pass a state from component Navbar.js
to the App.js
to do when I click outside the SideMenu()
in closes the navbar. How to fix this error? I passed the State props from parent to a child Navbar.js
and it doesn't close when I click outside Navbar
-Defined const [isSideMenuOpen, setIsSideMenuOpen] = useState(false);
in App.js
-Added props to pass to a child component <Navbar setIsSideMenuOpen={setIsSideMenuOpen} isSideMenuOpen={isSideMenuOpen} />
-Destructuring setIsSideMenuOpen
and isSideMenuOpen
in Navbar.js (check the code below)
App.js
import "../styles/globals.css";
import Navbar from "../comps/Navbar";
import { useState, useEffect, useRef } from "react";
let useClickOutside = (handler) => {
let domNode = useRef();
useEffect(() => {
let maybeHandler = (event) => {
if (!domNode.current?.contains(event.target)) {
handler();
}
};
document.addEventListener("mousedown", maybeHandler);
return () => {
document.removeEventListener("mousedown", maybeHandler);
};
});
return domNode;
};
function MyApp({ Component, pageProps }) {
const [isSideMenuOpen, setIsSideMenuOpen] = useState(false);
let domNode = useClickOutside(() => {
setIsSideMenuOpen(false);
});
return (
<div className="relative">
<Navbar
setIsSideMenuOpen={setIsSideMenuOpen}
isSideMenuOpen={isSideMenuOpen}
/>
<div ref={domNode}>
<Component {...pageProps} />
</div>
</div>
);
}
export default MyApp;
../components/Navbar.js
import { useState, useEffect, useRef } from "react";
import { HiMenuAlt1, HiOutlineX } from "react-icons/hi";
export default function Navbar({ isSideMenuOpen, setIsSideMenuOpen }) {
const showSideMenu = () => {
isSideMenuOpen ? setIsSideMenuOpen(false) : setIsSideMenuOpen(true);
};
return (
<div className="absolute z-40 w-full h-8 text-cyan-600 flex flex-row justify-between items-center text-2xl ">
<div className="brand-logo text-xl font-bold px-2 font-extrabold text-cyan-600">
Trener
</div>
<ul className="md:flex hidden menu-list text-xl font-bold ">
<li className="menu-list-item px-2">
<a href="/">Strona główna</a>
</li>
<li className="menu-list-item px-2">
<a href="#b">O mnie</a>
</li>
<li className="menu-list-item px-2">
<a href="#c">Plany treningowe</a>
</li>
</ul>
<button
onClick={() => {
showSideMenu();
}}
className="lg:hidden menu-button"
>
{isSideMenuOpen ? (
<HiOutlineX className="w-8 h-8 px-2 bg-red-600" />
) : (
<HiMenuAlt1 className="w-8 h-8 px-2" />
)}
</button>
{isSideMenuOpen ? SideMenu() : ""}
</div>
);
}
function SideMenu() {
return (
<div className="fixed z-20 w-1/2 sm:w-1/4 lg:hidden bg-gray-300 top-8 right-0 p-3">
{/* sagsa */}
<ul className="menu-list flex flex-col text-lg font-bold">
<li className="menu-list-item py-2 hover:bg-white hover:text-blue-700">
<a href="/">Strona główna</a>
</li>
<li className="menu-list-item py-2 hover:bg-white hover:text-blue-700">
<a href="/about">O mnie</a>
</li>
<li className="menu-list-item py-2 hover:bg-white hover:text-blue-700">
<a href="#c">Plany treningowe</a>
</li>
</ul>
</div>
);
}
CodePudding user response:
That's because you've defined setIsSideMenuOpen in child component which is Navbar.js
What you can do define
const [isSideMenuOpen, setIsSideMenuOpen] = useState(false)
in the App.js and then pass it as props to Navbar. That way you can handle the isSideMenuOpen from both the parent and child
CodePudding user response:
You can't pass the state and it's setter Function form child component to parent component, There are following approches you can do
Define the state, and its Setter function in App.js and then pass both state and it's setter as a props to Navbar.js and then use them here as a props.
Use State Lift up concept Make a combine parent component and and define
const [isSideMenuOpen, setIsSideMenuOpen] = useState(false);
here and pass this as a props to both component's App.js and Navbar.js.
- You can simple use redux to avoid state passing issue.