How to close dropdown menu using own useOnOutsideClick hook?

Viewed 189

I faced a problem with my mobile drowdown menu. I'd like to close dropdown by clicking outside (somewhere, let's say on titels above) of my button and dropdown items.

This is my example.

Menu

const Menu = () => {
  const [isMobileNavOpen, setMobileNavState] = useState(false);

  const mobileNavRef = useRef();

  useOnOutsideClick(mobileNavRef, () => {
    if (isMobileNavOpen) setMobileNavState(false);
  });

  const toggleMobileNav = () => {
    setMobileNavState(!isMobileNavOpen);
  };

  return (
    <div>
      <div className="dropdown" ref={mobileNavRef}>
        <button
          className="dropdown-btn"
          onClick={toggleMobileNav}
          type="button"
        >
          DROPDOWN BUTTON
        </button>
        {isMobileNavOpen && (
          <div
            className="dropdown-menu"
            onClick={() => setMobileNavState(false)}
          >
            <a className="dropdown-item" href="#">
              Item1
            </a>
            <a className="dropdown-item" href="#">
              Item2
            </a>
          </div>
        )}
      </div>
    </div>
  );
};

my hook useOnClickOutside

export const useOnOutsideClick = (ref, callback) => {
  const handleClick = (e) => {
    if (ref.current && ref.current.contains(e.target)) {
      callback();
      console.log("click");
    }
  };

  useEffect(() => {
    document.addEventListener("click", handleClick);

    return () => {
      document.removeEventListener("click", handleClick);
    };
  });
};

Please about any help!

1 Answers

Flip the contains logic of your useOutsideClick hook. You want to check of the click event originated from not within the target element the ref is attached to.

const handleClick = (e) => {
  if (!ref.current?.contains(e.target)) {
    callback();
    console.log("click");
  }
};

Edit how-to-close-dropdown-menu-using-own-useonoutsideclick-hook

Entire hook

export const useOnOutsideClick = (ref, callback) => {
  const handleClick = (e) => {
    if (!ref.current?.contains(e.target)) {
      callback();
      console.log("click");
    }
  };

  useEffect(() => {
    document.addEventListener("click", handleClick);

    return () => {
      document.removeEventListener("click", handleClick);
    };
  });
};
Related