PRASHANT VERMA
PRASHANT VERMA

Reputation: 135

hamburger toggle button not working react

import React, { useState, useEffect, useRef } from "react";
import { Link } from "react-router-dom";
import "./index.css";


const Navbar = () => {

    const [isMenuOpen, setIsMenuOpen] = useState(false);
    const toggle = () => setIsMenuOpen(!isMenuOpen);
    const ref = useRef()
    useEffect(() => {
        const checkIfClickedOutside = e => {
          if (isMenuOpen && ref.current && !ref.current.contains(e.target)) {
            setIsMenuOpen(false)
          }
        }
        document.addEventListener("mousedown", checkIfClickedOutside)
        return () => {
          document.removeEventListener("mousedown", checkIfClickedOutside)
        }
      }, [isMenuOpen])

    return (
        <>
            <header>

                <nav>
                    <div className="nav">

                        <div className="nav-brand">
                            <Link to="./" className="text-black">Website</Link>
                        </div>
                        <div className="toggle-icon" onClick={toggle}>
                            <i id="toggle-button" className={isMenuOpen ? 'fas fa-times' : 'fas fa-bars'} />
                        </div>
                        {isMenuOpen && (
                            <div className={isMenuOpen ? "nav-menu visible" : "nav-menu"} ref={ref}>
                                <ul className="main-menu">

                                    <li><Link to="./" onClick={toggle}>Home</Link></li>
                                    <li><Link to="./blog" onClick={toggle}>Blog</Link></li>
                                    <li className="drp">
                                        <p className="dropbtn">Find <i className="fa-solid fa-angle-down"></i></p>
                                        <ul className="dropdown-content">
                                            <li><Link to="./find/portable-keyboards" onClick={toggle}>Portable Keyboards</Link></li>
                                        </ul>
                                    </li>
                                    <li className="drp">
                                        <p className="dropbtn">More <i className="fa-solid fa-angle-down"></i></p>
                                        <ul className="dropdown-content">
                                            <li><Link to="./piano-notes" onClick={toggle}>Piano Notes</Link></li>
                                            <li><Link to="./chords" onClick={toggle}>Chords</Link></li>
                                            <li><Link to="./tools/metronome" onClick={toggle}>Metronome</Link></li>
                                        </ul>
                                    </li>
                                </ul>
                            </div>
                        )}
                    </div>
                </nav>  
            </header>

        </>
    )
}

export default Navbar;

Everything is working fine except the toggle button. The menu is not closing after opening it. The onClick={toggle} function is not working on the close icon. The menu will hide when someone clicks outside the menu component which is working fine. I tried a lot but didn't find any method to resolve it. Can someone try to solve this issue?

Upvotes: 1

Views: 974

Answers (1)

Drew Reese
Drew Reese

Reputation: 202668

Issue

The menu toggle button is outside the element you are attaching the outside click listener to, so when you are trying to close the menu the toggle callback and the checkIfClickedOutside handlers are cycling the isMenuOpen state.

Solution

Wrap both the menu button and the menu in a div for the ref to be attached to. There is also no reason really to check if isMenuOpen is true in the checkIfClickedOutside handler. If isMenuOpen is already false, enqueueing another state update to set it false is generally ignored by React. This allows you to remove it as a dependency.

Example:

const Navbar = () => {
  const [isMenuOpen, setIsMenuOpen] = useState(false);
  const toggle = () => setIsMenuOpen(!isMenuOpen);
  const ref = useRef();

  useEffect(() => {
    const checkIfClickedOutside = (e) => {
      if (!ref.current?.contains(e.target)) {
        setIsMenuOpen(false);
      }
    };
    document.addEventListener("mousedown", checkIfClickedOutside);
    return () => {
      document.removeEventListener("mousedown", checkIfClickedOutside);
    };

  }, []);

  return (
    <>
      <header>
        <nav>
          <div className="nav">
            <div className="nav-brand">
              <Link to="./" className="text-black">
                Website
              </Link>
            </div>
            <div ref={ref}> // <-- ref to this containing div
              <div className="toggle-icon" onClick={toggle}>
                <i
                  id="toggle-button"
                  className={isMenuOpen ? "fas fa-times" : "fas fa-bars"}
                />
              </div>
              {isMenuOpen && (
                <div className={isMenuOpen ? "nav-menu visible" : "nav-menu"}>
                  ....
                </div>
              )}
            </div>
          </div>
        </nav>
      </header>
    </>
  );
};

Edit hamburger-toogle-button-not-working-react

Upvotes: 2

Related Questions