Reputation: 678
I have a header menu for which I've submenu items. For example in the below the first item alone has submenu. I've to show the submenu on hovering only on the header menu which as submenu.But I'm getting the submenu on hovering all the header menu.I'm using tailwindcss for this and below is the code snippet.
headerdata.json
{
"headerData": [
{"text":"Home Applicances", "url":"homeappli","submenu":[
{
"submenuText":"Television",
"url":""
},
{
"submenuText":"Fridge",
"url":""
},
{
"submenuText":"Washing Machine",
"url":""
}
]},
{"text":"Mobiles & Accessories", "url":"mobile"},
{"text":"Discount Combos", "url":"disc"},
{"text":"Offers", "url":"offers"}
]
}
and JS :
import React, { useState } from "react";
// import './Header.styles';
import logo from "../../images/logo-dark.png";
import FavoriteBorderIcon from "@material-ui/icons/FavoriteBorder";
import ShoppingCartIcon from "@material-ui/icons/ShoppingCart";
import SearchIcon from "@material-ui/icons/Search";
import Avatar from "@material-ui/core/Avatar";
import LoginModal from "../Modal/LoginModal";
import headerData from "../../data/headerData.json";
function Header() {
const [openSearch, setOpensearch] = useState(false);
const [isUserLogged, setIsUserLogged] = useState(false);
const [showSubmenu , setShowSubmenu] = useState(false);
const handleSearch = () => {
setOpensearch(!openSearch);
};
const handleLogin = () => {
// Checking whether used loggedin using local storage logic
setIsUserLogged(true);
// return <LoginModal />
};
const closeModal = () => {
setIsUserLogged(false);
};
return (
<div className="fixed md:px-8 px-8 w-full z-10 bg-white shadow-md">
<div className="flex lg:justify-around md:my-3 md:flex-row sm:flex-row ">
<div className="flex justify-center items-center w-full">
<img src={logo} className="h-30 md:h-30 " alt="Ansar_logo" />
</div>
<div className="flex text-lg cursor-pointer h-10" onClick={handleLogin}>
<div className="px-2 whitespace-no-wrap flex items-center">
Sign In
</div>
<Avatar />
</div>
{isUserLogged && <LoginModal handleClose={closeModal} />}
</div>
<div className="flex lg:justify-around md:mb-6 md:flex-row sm:flex-row h-4">
<div className="flex justify-center items-center w-4/5">
{headerData?.headerData?.map((data) => {
return (
<div
onMouseEnter={() => setShowSubmenu(true)}
onMouseLeave={() => setShowSubmenu(false)}
className="px-5 cursor-pointer font-medium hover:text-green-900 hover:border-1 hover:border-solid hover:border-green-900 uppercase ">
{data.text}
</div>
);
})}
</div>
{showSubmenu && <div>
{headerData?.headerData[0].submenu.map((data) => {
return (
<li className="px-5 py-2
cursor-pointer relative font-medium bg-red-800 hover:text-green-900 uppercase list-none">
{data.submenuText}
</li>
);
})}
</div>
}
<div className="flex justify-end w-1/5">
<div className="pr-2 flex">
{openSearch && (
<input
type="search"
className=" w-auto border-b-2 px-8 py-4 -mt-3 border-black outline-none"
placeholder="Search product...."
/>
)}
<SearchIcon onClick={handleSearch} className="cursor-pointer" />
</div>
<div className="pr-2 flex flex-col place-items-center ">
<FavoriteBorderIcon className="cursor-pointer" />
</div>
<div className="flex flex-col place-items-center">
<ShoppingCartIcon className="cursor-pointer" />
</div>
</div>
</div>
</div>
);
}
export default Header;
Upvotes: 0
Views: 57
Reputation: 2321
You were not conditionally setting the onMouseOver callback. Instead you were setting state which was using the same submenu for every menu item.
Here is a simplified version of the fix you can mess around with:
json file:
{
"navbar": [
{
"text": "Home Applicances",
"url": "homeappli",
"submenu": [
{
"submenuText": "Television",
"url": ""
},
{
"submenuText": "Fridge",
"url": ""
},
{
"submenuText": "Washing Machine",
"url": ""
}
]
},
{ "text": "Mobiles & Accessories", "url": "mobile" },
{ "text": "Discount Combos", "url": "disc" },
{ "text": "Offers", "url": "offers" }
]
}
Javascript file (simplified)
import React, { useState } from "react";
import ReactDOM from "react-dom";
import headerData from "./headerData.json";
import "./styles.css";
function App() {
const [menuIndex, setMenuIndex] = useState(-1);
return (
<div id="navbarHolder">
{headerData.navbar.map((item, index) => {
return (
<div
key={index}
onMouseOver={
item.hasOwnProperty("submenu")
? () => setMenuIndex(index)
: () => setMenuIndex(-1)
}
>
{item.text}
</div>
);
})}
{menuIndex > -1 && (
<div>
{headerData.navbar[menuIndex].submenu.map((item) => {
return <li>{item.submenuText}</li>;
})}
</div>
)}
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Upvotes: 1
Reputation: 1634
So you had two bugs here:
Here is a fixed example: and also CodeSandbox
import React, { useState } from "react";
import "./styles.css";
const data = {
headerData: [
{
text: "Home Applicances",
url: "homeappli",
submenu: [
{
submenuText: "Television",
url: ""
},
{
submenuText: "Fridge",
url: ""
},
{
submenuText: "Washing Machine",
url: ""
}
]
},
{ text: "Mobiles & Accessories", url: "mobile" },
{ text: "Discount Combos", url: "disc" },
{ text: "Offers", url: "offers" }
]
};
export default function App() {
const [currentSubment, setCurrentSubmenu] = useState(-1);
return (
<div className="flex lg:justify-around md:mb-6 md:flex-row sm:flex-row h-4">
<div className="flex justify-center items-center w-4/5">
{data.headerData.map((data, index) => {
if (data.submenu) {
return (
<div
onMouseEnter={() => setCurrentSubmenu(index)}
onMouseLeave={() => setCurrentSubmenu(-1)}
className="px-5 cursor-pointer font-medium hover:text-green-900 hover:border-1 hover:border-solid hover:border-green-900 uppercase "
>
{data.text}
</div>
);
}
return (
<div className="px-5 cursor-pointer font-medium hover:text-green-900 hover:border-1 hover:border-solid hover:border-green-900 uppercase ">
{data.text}
</div>
);
})}
</div>
{currentSubment > -1 && (
<div>
{data.headerData[currentSubment].submenu.map((data) => {
return (
<li
className="px-5 py-2
cursor-pointer relative font-medium bg-red-800 hover:text-green-900 uppercase list-none"
>
{data.submenuText}
</li>
);
})}
</div>
)}
</div>
);
}
Upvotes: 1