Search code examples
javascriptreactjsheadermaterial-ui

How do i implement a dropdown header in Material-ui in react?


My main problem is that it's only rendering the last Menu Dropdown but i need different Menus (and you can see the text behind it faintly appearing). Am unsure how to pass the correct props / state to enable this

import React from 'react';
import {Button, Menu, MenuItem} from "@material-ui/core";

function Header(){
const [anchorEl, setAnchorEl] = React.useState(null);

const handleClick = (event) => {
    setAnchorEl(event.currentTarget);
};

const handleClose = () => {
    setAnchorEl(null);
};

return (
    <div>
        <Button aria-controls="sessions-menu" aria-haspopup="true" onClick={handleClick}>
            Sessions
        </Button>
        <Button aria-controls="store-menu" aria-haspopup="true" onClick={handleClick}>
            Store
        </Button>
        <Button aria-controls= "about-menu" aria-haspopup="true" onClick={About} href="/about">
            About
        </Button>
        <Button aria-controls="account-menu" aria-haspopup="true" onClick={handleClick}>
            Account
        </Button>
        <Menu
            id="sessions-menu"
            anchorEl={anchorEl}
            getContentAnchorEl={null}
            keepMounted
            open={Boolean(anchorEl)}
            onClose={handleClose}
        >
            <MenuItem onClick={Book} href="/sessions/book">Book a Session</MenuItem>
            <MenuItem onClick={Host} href="/sessions/host">[S] Host a session</MenuItem>
        </Menu>
        <Menu
            id="store-menu"
            anchorEl={anchorEl}
            getContentAnchorEl={null}
            keepMounted
            open={Boolean(anchorEl)}
            onClose={handleClose}
        >
            <MenuItem onClick={Purchase}>Purchase</MenuItem>
            <MenuItem onClick={Sell}>[S] Sell</MenuItem>
        </Menu>
        <Menu
            id="about-menu"
            anchorEl={anchorEl}
            keepMounted
            open={Boolean(anchorEl)}
            onClose={handleClose}
        ></Menu>
        <Menu
            id="account-menu"
            anchorEl={anchorEl}
            keepMounted
            open={Boolean(anchorEl)}
            onClose={handleClose}
        >
            <MenuItem onClick={Lessons}>My Lessons</MenuItem>
            <MenuItem onClick={Items}>My Purchases</MenuItem>
        </Menu>
    </div>
);
}
export default Header;

Any help or advice for a simpler way to achieve what i want would be swell


Solution

  • As given in documentation anchorEl - It's used to set the position of the menu. In your code you used same anchorEl for all menu and as a result it's only rendering the last Menu Dropdown.

    solution is to have anchorEl separate to each menu. for that you need to create scoped MenuButton component for each button with its menu.

    You can have separate component for each button with its menu (duplication) however it better have an array of menus and render it with single component(reusability).

    please check running code here https://codesandbox.io/s/header-menu-dropdown-e9e7p

    I will put Header and MenuButton code here if link not work.

    Header.js

    import React from "react";
    import MenuButton from "./MenuButton";
    
    const Header = () => {
      //added only two menu to demonstrate you can add more as per your requirement
      const menu = [
        {
          name: "Sessions",
          menuItems: [
            {
              name: "Book a Session",
              onClick: () => {},
              href:"" 
            },
            {
              name: "[S] Host a session",
              onClick: () => {},
              href:"" 
            }
          ]
        },
        {
          name: "Store",
          menuItems: [
            {
              name: "Purchase",
              onClick: () => {}
            },
            {
              name: "Sell",
              onClick: () => {}
            }
          ]
        }
      ];
      return menu.map((item, index) => <MenuButton key={index} menu={item} />);
    };
    export default Header;
    

    MenuButton.js (button with its menu)

    import React from "react";
    import { Button, Menu, MenuItem } from "@material-ui/core";
    
    const MenuButton = ({ menu }) => {
      const [anchorEl, setAnchorEl] = React.useState(null);
    
      const handleClick = (event) => {
        setAnchorEl(event.currentTarget);
      };
    
      const handleClose = () => {
        setAnchorEl(null);
      };
    
      return (
        <>
          <Button
            aria-controls={`${menu.name}-menu`}
            aria-haspopup="true"
            onClick={handleClick}
          >
            {menu.name}
          </Button>
          <Menu
            id={`${menu.name}-menu`}
            anchorEl={anchorEl}
            getContentAnchorEl={null}
            keepMounted
            open={Boolean(anchorEl)}
            onClose={handleClose}
          >
            {menu.menuItems.map((item) => (
              <MenuItem onClick={item.onClick} href={item.href}>
                {item.name}
              </MenuItem>
            ))}
          </Menu>
        </>
      );
    };
    export default MenuButton;