rodcunha
rodcunha

Reputation: 431

setTimeout timer stored and cleared via state (or non global)

I am trying to open a popup only after the user mouses over an icon for one second to prevent triggering it by accident.

The only way I found to do this was using setTimeout on a handler function the problem is that for this to work I have to declare a global variable to the React component. This works but I'd rather not use a global variable this way.

let timer; 

export default class Users extends Component {
  state = {
      popoverOpen: false,
    };


  handleMouseOver = (e) => {
    e.stopPropagation();
    switch (e.type) {
      case 'mouseover':
        clearTimeout(timer);
        timer =
          setTimeout(() => {
            this.setState({
              popoverOpen: true
            });
          }, 1000);
        break;
      case 'mouseout':
        clearTimeout(timer);
        break;
      default:
        console.log(e.type);
        break;
    }
  };

Is there a way to set and clear the timeout using the local state or if not is there a better way to do this that is escaping me?

Thank you.

Upvotes: 3

Views: 633

Answers (1)

Orelsanpls
Orelsanpls

Reputation: 23545

Using the upper class to store the timer and state data it look like :

class A {
  constructor() {
    this.state = false;
  }

  func() {
    if (this.state) {
      console.log('push the call');

      clearTimeout(this.timer);
    } else {
      console.log('initial call');
    }

    this.state = true;

    this.timer = setTimeout(() => {
      this.state = false;

      console.log('Call ended');
    }, 500);
  };
};

const a = new A();

a.func();

for (let i = 0; i < 5; i += 1) {
  setTimeout(() => a.func(), i * 200);
}



Or if you do not want to pollute your class, wrap the function inside of an IIFE where you can store data

I've created a snippet example and then an usable react example to put on your code (because handleMouseOver = (e) => { do not work in plain js)

class A {};

const a = new A();

a.func = (() => {
  let state = false;
  let timer;
  
  return () => {
      if (state) {
        console.log('push the call');

        clearTimeout(timer);
      } else {
        console.log('initial call');
      }

      state = true;

      timer = setTimeout(() => {
        state = false;

        console.log('Call ended');
      }, 500);
  };
})();

for (let i = 0; i < 5; i += 1) {
  setTimeout(() => a.func(), i * 200);
}


class A {
  func = (() => {
    let state = false;
    let timer;

    return () => {
      if (state) {
        console.log('push the call');

        clearTimeout(timer);
      } else {
        console.log('initial call');
      }

      state = true;

      timer = setTimeout(() => {
        state = false;

        console.log('Call ended');
      }, 500);
    };
  })();
};

Upvotes: 2

Related Questions