Said Benmoumen
Said Benmoumen

Reputation: 343

check if element still has mouseenter after delay

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

Answers (1)

Drew Reese
Drew Reese

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]);

Edit pedantic-flower-wsp3z

Upvotes: 2

Related Questions