react-use icon indicating copy to clipboard operation
react-use copied to clipboard

Allow passing an array of refs to useClickAway

Open matthova opened this issue 5 years ago • 7 comments

Is your feature request related to a problem? Please describe. For my use case I have a button that opens a modal. Once the modal is open, I want clicking away to close the modal, but if I click on the modal toggle button, I get two conflicting commands - from the modal useClickAway event and from the button's onClick event.

Describe the solution you'd like If I could pass an array of refs then I could prevent the behavior described above by passing a ref for the modal as well as the button.

Describe alternatives you've considered I had tried making the modal toggle button only fire when the modal is closed, however that still ran into a race-condition, even when setting the mouse events to ['mouseup', 'touchend']. Another alternate solution would be to use a setTimeout, however I'd prefer to not use that.

matthova avatar Mar 11 '20 00:03 matthova

Oh man, I can't tell you the number of times this has happened to me outside of this library! I'll try to fix this weekend, feel the pain!

idfunctor avatar Mar 21 '20 03:03 idfunctor

@blnk-space any luck? I've run into a second instance where this would be nice: I'm using a portal and need to ref the portal as well. May try to timebox a solution tomorrow

matthova avatar Apr 10 '20 08:04 matthova

PR: https://github.com/streamich/react-use/pull/1125

matthova avatar Apr 10 '20 17:04 matthova

For those who are looking for a solution to this problem You can check if your dropdown is already open and then close it

Example:

Wrong:

const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const ref = useRef();

useClickAway(ref, () => setIsDropdownOpen(false));

<div className="container" ref={ref}>
    <div className="dropdown" />
</div>

Correct:

const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const ref = useRef();

useClickAway(ref, () => isDropdownOpen ? setIsDropdownOpen(false) : null);

<div className="container" ref={ref}>
    <div className="dropdown" />
</div>

Afgan0r avatar Oct 02 '20 06:10 Afgan0r

I'm facing exactly this problem and it always takes like 3-4 additional internal state checking just to close a modal correctly, especially when I have to move modal to portal.

Really looking forward to the PR.

Many thanks.

sangdth avatar Dec 27 '20 20:12 sangdth

I have a similar use case, and for now, I'm using a ref on the element to ignore to work around it.

If the element contains children you'll need to prevent clicks on them, for example using pointer-events: none.

const [isSidebarOpen, setIsSidebarOpen] = useState(false);
const navRef = useRef(null);
const navButtonRef = useRef(null);

useClickAway(navRef, (event) => {
  const clickedNavButton = event.target === navButtonRef.current;

  if (!clickedNavButton) {
    setIsSidebarOpen(false);
  }
});

sarahdayan avatar Jun 23 '21 19:06 sarahdayan

Hi, everyone. I added this feature to useClickAway (https://github.com/streamich/react-use/pull/2593). Waiting review.

@matthova I saw your PR, but I don't understand why it still hasn't merged.

philipprus avatar Aug 29 '24 09:08 philipprus