Home > Net >  Outside click event listener isnt working: Reactjs
Outside click event listener isnt working: Reactjs

Time:11-17

I am implementing a custom side panel that opens up from the right. I am able to achieve show and hide of the panel on a click of a button. But I want the same thing to be hidden when i click outside. I am attaching the outside click handler, And when I do that it is not even showing up. Can someone help

https://codesandbox.io/s/react-sliding-pane-v2-4xuj57?file=/src/SlideDrawer.jsx:100-173

import React, { useRef, useCallback, useEffect } from "react";
import "./styles.css";

export default function SlideDrawer({ show, setDrawerOpen }) {
  const sideMenuRef = useRef(null);

  const onOutsideClick = useCallback(() => {
    setDrawerOpen(false);
  }, [setDrawerOpen]);

  useEffect(() => {
    document.addEventListener("click", onOutsideClick);
    return () => document.removeEventListener("click", onOutsideClick);
  }, [onOutsideClick]);

  return (
    <div ref={sideMenuRef} className={`panel ${show && "slidein"}`}>
      I am sliding
    </div>
  );
}

import React, { useState } from "react";
import ReactDOM from "react-dom";
import SlideDrawer from "./SlideDrawer.jsx";
import "./styles.css";

function App() {
  const [drawerOpen, setDrawerOpen] = useState(false);

  return (
    <div className="box">
      <SlideDrawer show={drawerOpen} setDrawerOpen={setDrawerOpen} />
      <button onClick={() => setDrawerOpen((prev) => !prev)}>Click me!</button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

CodePudding user response:

What happens:

If you click the button, drawerOpen is set to true and immediately set to false again. You can verify by adding

  React.useEffect(() => {
    console.log(drawerOpen)
  }, [drawerOpen])

to index.js.

To fix this, you'll need to check if the click targeted the button in your eventListener.

You can solve it by giving the button an id:

      <button id="openPanelButton" onClick={() =>setDrawerOpen((prev) => !prev)}>Click me!</button>

and then checking the click like this:

import React, { useRef, useCallback, useEffect } from "react";
import "./styles.css";

export default function SlideDrawer({ show, setDrawerOpen }) {
  const sideMenuRef = useRef(null);

  const handleClick = useCallback((event) => {
    if (event.target.id !== "openPanelButton" && event.target !== sideMenuRef.current) {
      setDrawerOpen(false);
    }
  }, [setDrawerOpen]);

  useEffect(() => {
    document.addEventListener("click", handleClick);
    return () => document.removeEventListener("click", handleClick);
  }, [handleClick]);

  return (
    <div ref={sideMenuRef} className={`panel ${show && "slidein"}`}>
      I am sliding
    </div>
  );
}

CodePudding user response:

To achieve behavior that you want, you need to change event that you are looking for from "click" to "mousedown" like this:

document.addEventListener("mousedown", onOutsideClick);

This way, same click wouldn't trigger open and close at the same time.

Also update your onClick that open your drawer and check if it already opened.

That way it will work

  • Related