Reputation: 343
i made some blocks with a mouseenter
and mouseleave
<button onMouseEnter={this.MouseEnter}>hover</button>
MouseEnter(e) {
setTimeout(() => {
//check if mouse over still on this element
// do action
}, 600);
}
the problem is when i move the blocks very fast the last block detects the mouseenter before the timeout and do the action even if i'm not hovering on the block which is a bug, i want to make it the action run only after 500ms
of hover on block.
p.s: i'm working with react.js
Upvotes: 3
Views: 2703
Reputation: 202751
The piece you're really missing is the invalidation of the timeout callback if the mouseLeave
event is triggered. For this you need to hold on to the returned setTimeout
value in order to call clearTimeout
before the timer expires (or if the component unmounts!!)
The following is the basic machinery in a class-based component:
state = {
hovered: false
};
timer;
mouseEnterHandler = () => this.setState({ hovered: true });
mouseLeaveHandler = () => this.setState({ hovered: false });
onTimeout = () => {
// Do action
};
clearTimer = () => {
clearTimeout(this.timer);
};
// Here's the meat:
// If state updates, then componentDidUpdate is called,
// if the new hovered state is true, set timeout and save the
// returned reference, else clear the timeout using the saved
// timer reference.
componentDidUpdate() {
const { hovered } = this.state;
if (hovered) {
this.timer = setTimeout(this.onTimeout, 500);
} else {
this.clearTimer();
}
}
// This is component cleanup, if the component unmounts before
// the timer expires you may not want the "Do action" to fire,
// so we go ahead and clear the timeout so you're not accidentally
// accessing state/props of an unmounted component.
componentWillUnmount() {
this.clearTimer();
}
The following is the equivalent functional component logic:
const [hovered, sethovered] = useState(false);
const mouseEnterHandler = () => sethovered(true);
const mouseLeaveHandler = () => sethovered(false);
const onTimeout = () => {
// Do action
};
useEffect(() => {
const timer = hovered && setTimeout(onTimeout, 500);
return () => {
clearTimeout(timer);
};
}, [hovered]);
Upvotes: 2