Material-UI button requires 3 clicks before it will render menu

Viewed 276

Problem summary:
This is a React app (Next.js) using Material-UI for styling components. I'm having issues with a menu button that I've created. When I click on the button to fire the menu, it takes 3 clicks before the menu will render.

Expected result:
Menu should open on the first click.

Actual result:
A working example can be seen on my website https://pdill.dev. The menu is located in the sidebar on the right side. On the first click, a small white box appears where the menu will appear, but without the menu options. The second click closes the nonexistent menu. On the third click, the menu renders.

Troubleshooting:
I tried adding a console.log() function within the handleClick function and it showed the click handler firing on the first click even though the menu doesn't render. I tried to implement a useEffect hook for the event handler, but it didn't seem to help either. It only made the event handler unreachable. My implementation may have been incorrect of course, but I'm trying to see if there's something else that I'm missing.

Code:

export default function SimpleMenu () {
  const [anchorEl, setAnchorEl] = React.useState(null)
  const menuOptions = [
    { name: 'Home', href: 'https://pdill.dev/#top' },
    { name: 'About me', href: 'https://pdill.dev/#About' },
    { name: 'Projects', href: 'https://pdill.dev/#projects' },
    { name: 'Contact', href: 'mailto:paul@pdill.dev' },
    { name: 'Resume' }
  ]
  const [list, setList] = useState([])
  const [isActive, setIsActive] = useState(false)
  const newList = []

  const listMenuOptions = () => {
    Object.values(menuOptions).forEach((item, index) => {
      newList.push(<MenuItem key={index} onClick={handleClose}><a href={item.href}>{item.name}</a></MenuItem>)
    })
    return newList
  }

  function handleClick (event) {
    setAnchorEl(event.currentTarget)
    listMenuOptions()
    console.log(newList) //Added to show the list is firing
    setIsActive(!isActive)
    isActive ? setList(newList) : setList(null)
  }

  function handleClose () {
    setAnchorEl(null)
  }

  return (
    <div>
      <Button aria-controls="simple-menu" aria-haspopup="true" onClick={handleClick}>
      ☰
      </Button>
      <Menu
        id="simple-menu"
        anchorReference="anchorEl"
        anchorEl={anchorEl}
        getContentAnchorEl={null}
        anchorOrigin={{
          vertical: 'bottom',
          horizontal: 'left'
        }}
        transformOrigin={{
          vertical: 'top',
          horizontal: 'right'
        }}
        keepMounted
        open={Boolean(anchorEl)}
        onClose={handleClose}
      >
        {list}
      </Menu>
    </div>
  )
}
1 Answers

Issues

You construct a new list every render, but then conditionally toggle your list state between a populated list and an empty one. The behavior I see is every other time the menu is clicked it either displays the menu items or the empty white square.

Solution

Just set the anchorEl state and render the list via array mapping in the render return. No need for the isActive and list state.

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

  function handleClick(event) {
    setAnchorEl(event.currentTarget);
  }

  function handleClose() {
    setAnchorEl(null);
  }

  return (
    <div>
      <Button
        aria-controls="simple-menu"
        aria-haspopup="true"
        onClick={handleClick}
      >
        ☰
      </Button>
      <Menu
        id="simple-menu"
        anchorReference="anchorEl"
        anchorEl={anchorEl}
        getContentAnchorEl={null}
        anchorOrigin={{
          vertical: "bottom",
          horizontal: "left"
        }}
        transformOrigin={{
          vertical: "top",
          horizontal: "right"
        }}
        keepMounted
        open={Boolean(anchorEl)}
        onClose={handleClose}
      >
        {Object.values(menuOptions).map((item, index) => (
          <MenuItem key={index} onClick={handleClose}>
            <a href={item.href}>{item.name}</a>
          </MenuItem>
        ))}
      </Menu>
    </div>
  );
}

Edit material-ui-button-requires-3-clicks-before-it-will-render-menu

Related