I have a <Group/>
element containing a rectangle and a set of icons on top of the group that should only be visible if the user moves the cursor within the boundaries of that <Group/>
's contents. Wether the icons are being shown or not is triggered by an onMouseOver
and onMouseOut
event handler attached to the <Group/>
object. I use a useState
hook to save the hover state and hide/show the icons.
Displaying the icons onMouseOver
works fine. But whenever the mouse cursor hovers over an icon, the onMouseOut
event of the <Group/>
is triggered, thus hiding the icons. Moving the mouse over an icon shows/hides them in rapid succession (flashing).
Is there a way to force the <Group/>
to not trigger an onMouseOut
event if the cursor is still actually within it's area but on top of an icon (event bubbling?)?
It is possible to workaround this by using React.useRef()
to store the hover state of the elements when they change and use the reference within a delayed function to decide what to do. In essence, something like this:
Setting up state, references and updating refs:
...
const [isGroupHover, setIsGroupHover] = useState(false);
const [isContextMenuHover, setIsContextMenuHover] = useState(false);
const isContextMenuHovereRef = useRef(isContextMenuHover);
const isGroupHoverRef = useRef(isGroupHover);
useEffect(() => {
isContextMenuHovereRef.current = isContextMenuHover;
isGroupHoverRef.current = isGroupHover;
}, [isGroupHover, isContextMenuHover]);
...
Intercepting the <Group/>
's onMouseOut
event
...
const onMouseOut = (e): void => {
setTimeout(() => {
if (!isContextMenuHovereRef.current) {
setIsGroupHover(false);
}
}, 350);
};
...
A function (setIsContextMenuHover()
) is passed down to the context menu component via prop. This way, the context menu can pass it's own hover-state up the chain.
...
<ContextMenu setOnHover={setIsContextMenuHover} />
...
Essentially, this prevents the hover state of the <Group/>
from being changed if the context menu is still visible or hovered over. A bit unwieldy - but it works.