I am coding a FlyoutManager from which I can toggle every flyout menus in react app. I am trying to set the property to close when clicking outside. I found on another stackoverflow question that my clicking-outside function is triggered when I click the button to close it so it re-opens the flyout menu because it toggles the menu state twice.
Have you got some ideas to fix my problem ?
Here is the Header code simplified to my problem :
export const Header = () => {
const {toggleFlyout} = useFlyout();
return (
<header>
<div>
/*
...
Other components
*/
<nav>
/*
...
Other buttons
*/
<button id="UserFlyout" onClick={() => toggleFlyout("UserFlyout")}>
User-logo
</button>
</nav>
</div>
</header>
);
};
Here is the FlyoutContext Folder which contains the toggle function :
export const FlyoutContext = createContext();
export const FlyoutProvider = ({children}) => {
const [flyout, setFlyout] = useState(null);
const [isOpen, setIsOpen] = useState(false)
const toggleFlyout = name => {
setIsOpen(!isOpen);
if (!isOpen) {
setFlyout(name);
} else {
setFlyout(null);
}
}
return (
<FlyoutContext.Provider value={{flyout, toggleFlyout}}>
{children}
</FlyoutContext.Provider>
);
};
export const useFlyout = () => useContext(FlyoutContext);
Here is the FlyoutManager Folder
const FlyoutList = {
UserFlyout: UserFlyout
};
export const FlyoutManager = () => {
const {flyout, toggleFlyout} = useFlyout();
const flyoutRef = useRef(null);
const Flyout = FlyoutList[flyout];
useEffect(() => {
const handler = event => {
if (flyoutRef.current !== null && !flyoutRef.current.contains(event.target)) {
toggleFlyout(flyout);
}
};
document.addEventListener('mousedown', handler);
return () => {
document.removeEventListener('mousedown', handler);
};
}, [flyoutRef, flyout, toggleFlyout]);
if (!flyout) return null;
return (
<Flyout flyoutRef={flyoutRef}>
<div ref={flyoutRef}>
user flyout
</div>
</Flyout>
);
};
Thanks a lot for your help
Some ideas might be to check if the mousedown event target is not the button. But because I use a context I can’t access the id button in the FlyoutContext.
2
Answers
Would it be crappy if I keep the
open
flag to use is as a condition in the button callback function like so :In fact, dividing the
toggleFlyout
function doesn't change anything regarding the double toggling when I click the header button to close the flyout.You’ve got two options, one is quite diffucult while the other is really simple:
toggleFlyout
into two idempotent functions.You can also entriely skip the
open
flag since it always comes together with the name, so if there is no name it means no flyout is open: