setTimeout计时器通过状态(或非全局)存储和清除

时间:2019-05-16 14:47:40

标签: javascript reactjs

我仅在用户将鼠标悬停在图标上一秒钟之后才尝试打开弹出窗口,以防止意外触发它。

我发现做到这一点的唯一方法是在处理程序函数上使用setTimeout,问题是,要使其正常工作,我必须向React组件声明一个全局变量。这行得通,但我宁愿不以这种方式使用全局变量。

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;
    }
  };

是否有一种方法可以使用本地状态设置和清除超时,或者如果没有更好的方法可以使我逃避呢?

谢谢。

1 个答案:

答案 0 :(得分:2)

使用上层类来存储计时器和状态数据,如下所示:

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



或者如果您不想污染您的类,请将函数包装在可以存储数据的IIFE内

我创建了一个片段示例,然后创建了一个可用的react示例以放入您的代码中(因为handleMouseOver = (e) => {在纯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);
    };
  })();
};