Home > Mobile >  toggle() isnt't working like it suppose to be
toggle() isnt't working like it suppose to be

Time:01-01

When I click the hamburger menu button I want both .menu-btn .menu-mob the menu button and the navigation menu the have to is-active class and .sqr to have the class .hidden when the other two are active. That's why I used toggle() to toggle all these classes, but for some reason it is not working.

Link to all code in repo

Note that I'm using react and tailwind and some vanilla css

const showNav = () => {
    const menuBtn = document.querySelector('.menu-btn')
    const navbar = document.querySelector('.menumob')
    const sqr = document.querySelector('.sqr')

    menuBtn.addEventListener('click', () => {
      menuBtn.classList.toggle('is-active')
      navbar.classList.toggle('is-active')
      sqr.classList.toggle('hidden')
    })
 <button  onClick={showNav()}>
            <div ></div>
 </button>
 .hamburger.is-active::before {
    transform: rotate(-45deg) translate(-8px, 6px);
 }

 .hamburger.is-active::after {
    transform: rotate(45deg) translate(-9px, -8px);
 }

 .hamburger.is-active .bar {
    opacity: 0;
 }


 .menumob {
    position: relative;
    top:0;
    left:100%;
    transition: 0.4s;
 }

 .menumob.is-active {
    left:0;
 }

CodePudding user response:

Given that you are using React you should be leveraging React's DOM handling rather than manually manipulating it yourself. For your specific situation all you need is a single boolean state storing whether the menu is active or not and then using that variable you can conditionally include the relevant styles, or even conditionally render elements instead of hiding them.

const Nav = () => {
  const [isActive, setIsActive] = React.useState(false);

  const toggleNav = () => {
    setIsActive(isActive => !isActive);
  };

  return (
    <nav className='flex flex-col justify-center h-screen md:h-screen md:mb-36 max-md:relative'>
      {/* MOBILE MENU */}
      <div
        className={'menumob container flex flex-col justify-center bg-black text-white h-screen w-screen md:hidden'
            (isActive
            ? ' is-active'
            : '')}
      >
      </div>

      {/* Humberguer Menu */}
      <button
        className={'menu-btn hamburger  absolute top-0 right-0 md:hidden'
            (isActive
            ? ' is-active'
            : '')}
        onClick={() => showNav()}
      >
        <div class='bar'></div>
      </button>

      {/* Imerses experiences */}
      {/* conditionall rendering with AND short-circuit */}
      {!isActive
        && (
          <div className='sqr container mx-auto my-0 top-1/2 mt-10 xl:px-56 max-md:absolute max-md:top-1/3'>
          </div>
        )}
    </nav>
  );
};

see related question: React Js conditionally applying class attributes

and the documentation:

CodePudding user response:

It's a bad idea to set up an event listener inside an onclick event. Every time you click, a new listener will be created causing the code to fire multiple times on each click.

In your code, the first time you click the event listener will be created but the code inside the listener won't run. The second time you click, the code inside the listener should run, but another listener will be created. The third time you click, the code inside the listener will run twice (toggling the class twice), and adding another listener. (And repeat for each click.)

The event listener is not needed at all, because the showNav function only runs when the hamburger menu item is clicked - because of onClick={showNav()} in the HTML. Try changing the code to this and see if it works:

const showNav = () => {
  const menuBtns = document.querySelector('.menu-btn')
  const navbars = document.querySelector('.menumob')
  const sqrs = document.querySelector('.sqr')

  menuBtn.classList.toggle('is-active')
  navbar.classList.toggle('is-active')
  sqr.classList.toggle('hidden')
};

Also, note that document.querySelector returns only the first matching element, so if you have more than one element with the class .menu-btn, .menumob or .sqr then not all of them will be updated.

  • Related