R
Reactiflux

✅ – ✅ – dmikester1 – 16-36 Sep 26

✅ – ✅ – dmikester1 – 16-36 Sep 26

Ddmikester19/26/2023
I have an OutsideClickTrigger hook I have found that I am utilizing to hide a filter menu whenever the user clicks outside the menu. There is a filters button that I am using to show the filters menu like this: onClick={() => setShowFilters(!showFilters)}. Now the issue is that when the filters menu is open, and I click on the filters button again to close it, it does not work or maybe it closes it quickly and then OutsideClickTrigger gets run and it shows it again. Last time I was able to fix this by wrapping the button and the menu in the hook component. That won't work this time because of the structure of my html. I'm thinking I somehow need to also pass the button element into that hook so it checks if that was the element clicked. Here is my OutsideClickTrigger hook component:
import React, { useRef, useEffect } from 'react';
import PropTypes from 'prop-types';

/**
* Hook that alerts clicks outside of the passed ref
*/
const useOutsideTrigger = (ref, onClick) => {
useEffect(() => {
/**
* Alert if clicked on outside of element
*/
function handleClickOutside(event) {
if (ref.current && !ref.current.contains(event.target)) {
onClick();
}
}
// Bind the event listener
document.addEventListener('mousedown', handleClickOutside);
return () => {
// Unbind the event listener on clean up
document.removeEventListener('mousedown', handleClickOutside);
};
}, [ref]);
};

/**
* Component that alerts if you click outside of it
*/
const OutsideTrigger = (props) => {
const wrapperRef = useRef(null);
useOutsideTrigger(wrapperRef, props.onClick);

return <div ref={wrapperRef}>{props.children}</div>;
};

OutsideTrigger.propTypes = {
children: PropTypes.element.isRequired
};

export default OutsideTrigger;
import React, { useRef, useEffect } from 'react';
import PropTypes from 'prop-types';

/**
* Hook that alerts clicks outside of the passed ref
*/
const useOutsideTrigger = (ref, onClick) => {
useEffect(() => {
/**
* Alert if clicked on outside of element
*/
function handleClickOutside(event) {
if (ref.current && !ref.current.contains(event.target)) {
onClick();
}
}
// Bind the event listener
document.addEventListener('mousedown', handleClickOutside);
return () => {
// Unbind the event listener on clean up
document.removeEventListener('mousedown', handleClickOutside);
};
}, [ref]);
};

/**
* Component that alerts if you click outside of it
*/
const OutsideTrigger = (props) => {
const wrapperRef = useRef(null);
useOutsideTrigger(wrapperRef, props.onClick);

return <div ref={wrapperRef}>{props.children}</div>;
};

OutsideTrigger.propTypes = {
children: PropTypes.element.isRequired
};

export default OutsideTrigger;
In this section: if (ref.current && !ref.current.contains(event.target)) { onClick(); } I think I also need to check if the button was clicked.
Solution:
Message Not Public
Sign In & Join Server To View
Jump to solution
UUUnknown User9/26/2023
3 Messages Not Public
Sign In & Join Server To View
Ddmikester19/26/2023
I thought this was kind of a "click away component". I am wrapping my stuff in it like this: <OutsideTrigger onClick={() => setShowFilters(false)}> I can remove the prop types 🙂
UUUnknown User9/26/2023
2 Messages Not Public
Sign In & Join Server To View
Ddmikester19/26/2023
So you are saying rewrite the logic in useOutsideTrigger ?
UUUnknown User9/26/2023
2 Messages Not Public
Sign In & Join Server To View
Ddmikester19/26/2023
OK, so I would wrap my menu and my button with that component?
UUUnknown User9/26/2023
Message Not Public
Sign In & Join Server To View
Ddmikester19/26/2023
Cool, I'll give it a try and report back!
UUUnknown User9/26/2023
Message Not Public
Sign In & Join Server To View
Ddmikester19/26/2023
I renamed it from modal, but this is how I wrapped my filters menu: <OutsideClickHook onClickAway={() => setShowFilters(false)}> when I click outside the menu, it does not dissapear
UUUnknown User9/26/2023
2 Messages Not Public
Sign In & Join Server To View
Ddmikester19/26/2023
<OutsideClickHook onClickAway={() => setShowFilters(false)}>
<div
className={`column-filters ${
showFilters ? 'show' : 'hide'
}`}
>
<h4 className={'title'}>Filters</h4>
...
<OutsideClickHook onClickAway={() => setShowFilters(false)}>
<div
className={`column-filters ${
showFilters ? 'show' : 'hide'
}`}
>
<h4 className={'title'}>Filters</h4>
...
and above that section:
<button
className={`btn ${
currentColumnFilters
? 'btn-outline-success'
: 'btn-outline-secondary'
}`}
onClick={() => setShowFilters(!showFilters)}
>
<FontAwesomeIcon
icon={'fa-regular fa-filter' as IconProp}
/>{' '}
Filter{' '}
</button>
<button
className={`btn ${
currentColumnFilters
? 'btn-outline-success'
: 'btn-outline-secondary'
}`}
onClick={() => setShowFilters(!showFilters)}
>
<FontAwesomeIcon
icon={'fa-regular fa-filter' as IconProp}
/>{' '}
Filter{' '}
</button>
UUUnknown User9/26/2023
2 Messages Not Public
Sign In & Join Server To View
Ddmikester19/26/2023
are those bootstrap classes or something different?
UUUnknown User9/26/2023
Message Not Public
Sign In & Join Server To View
Ddmikester19/26/2023
ok
UUUnknown User9/26/2023
Message Not Public
Sign In & Join Server To View
Ddmikester19/26/2023
i'd ideally like to fade it in/out
Solution
UUUnknown User9/26/2023
Message Not Public
Sign In & Join Server To View
Ddmikester19/26/2023
oh i see i'll try that Is this div meant to take up the entire page? <div onClick={onClickAway} className="flex h-full w-full flex-col items-center justify-center bg-black/50" >
UUUnknown User9/26/2023
Message Not Public
Sign In & Join Server To View
Ddmikester19/26/2023
so wherever i click, i will be clicking that div?
UUUnknown User9/26/2023
Message Not Public
Sign In & Join Server To View
Ddmikester19/26/2023
I think that is my issue gonna be tricky to figure out the positioning of my menu with that though
Ddmikester19/26/2023
No description
Ddmikester19/26/2023
The filters menu is under the Filter button
UUUnknown User9/26/2023
4 Messages Not Public
Sign In & Join Server To View
Ddmikester19/26/2023
not finding one, but something like this?
{showFilters && (
<>
<div className={'full-overlay z-1'} onClick={() => setShowFilters(false)}></div>
<div className={'column-filters z-2'} onClick={ev => ev.stopPropagation()}>
<h4 className={'title'}>Filters</h4>
{showFilters && (
<>
<div className={'full-overlay z-1'} onClick={() => setShowFilters(false)}></div>
<div className={'column-filters z-2'} onClick={ev => ev.stopPropagation()}>
<h4 className={'title'}>Filters</h4>
oh i wasn't gonna use children something like that? think I got it!!! I had to set position: fixed on that overlay and now it is going full width and height.
UUUnknown User9/26/2023
3 Messages Not Public
Sign In & Join Server To View
Ddmikester19/26/2023
Thank you so much igaul! That was a tricky one! Never would have thought of that stopPropagation trick.
UUUnknown User9/28/2023
2 Messages Not Public
Sign In & Join Server To View

Looking for more? Join the community!

R
Reactiflux

✅ – ✅ – dmikester1 – 16-36 Sep 26

Join Server