setInterval定时器在ReactJS的render()中不能正常工作

setInterval timer not working properly in render() of ReactJS

本文关键字:不能 常工作 工作 定时器 ReactJS render setInterval      更新时间:2023-09-26

我在React组件中有一个倒计时计时器,它的计数为10秒。如果在这10秒内组件接收到后端数据,计时器将停止。如果没有,它将计数到0,此时页面将刷新,并再次计数,以此类推,直到接收到数据。我的代码如下:

constructor() {
    ...
    this.counter = 10;
    ...
}
render() {
    const interval = setInterval(() => {
        const result = this.state.data;
        if (result) {
            this.setState({
                resultsReceived: true
            });
            clearInterval(interval);
        } else {
            this.setState({
                resultsReceived: false
            });
            this.counter = this.counter - 1;
            if (this.counter === 0) {
                window.location.reload();
            }
        }
    }, 1000);

问题是,计时器似乎不是每秒递减的。相反,它的行为是不稳定的——从10到7,它非常快,然后它可能挂起,甚至在0之后继续,也就是负的。页面正在重新加载。这段代码是错误的,还是与React的状态有关的问题?任何帮助都太好了!

更新:

我把代码改成了:

constructor() {
    this.state = {
        ...
        interval: '',
        counter: 10
    };
}
componentWillMount() {
    $.ajax({
        url: this.props.api,
        datatype: 'json',
        cache: false,
        success: (data) => {
            this.setState({ data });
        }
    });
    const interval = setInterval(() => {
        const results = this.state.data;
        if (results) {
            this.setState({
                resultsReceived: true
            });
            clearInterval(this.state.interval);
        } else {
            this.setState({
                resultsReceived: false
            });
            let counter;
            counter = this.state.counter - 1;
            this.setState({ counter });
            if (this.state.counter === 0) {
                window.location.reload();
            }
        }
    }, 1000);
    this.setState({ interval });
}
componentWillUnmount() {
    clearInterval(this.state.interval);  
}

它比以前更好,因为计时器第一次工作正常-它每1秒从10到0。然而,即使在10秒后数据还没有加载,计时器再次从10开始计时,它达到9,然后停止,直到数据最终加载。

我不知道为什么会发生这种情况,但我肯定你的代码有点奇怪。

  1. 首先,保持你的间隔到state是非常奇怪的。相反,将它保留在组件实例中,以便您可以轻松地清除它

  2. 不设置数据,用间隔检查。您可以在api请求完成时释放interval,并将数据设置为state。

  3. 组件被解散前总是清除间隔

这就是我的建议。

constructor() {
  ...
  this.interval = null
  this.state = { counter: 10 }
  ...
}
componentWillMount() {
  $.ajax({
    url: this.props.api,
    datatype: 'json',
    cache: false,
    success: (data) => {
      this.setState({ data })
      clearInterval(this.interval);
    },
  });
  this.interval = setInterval(() => {
    if (counter <= 0) {
      clearInterval(this.interval);
      location.reload();
      return;
    }
    this.setState({
      counter: this.state.counter - 1,
    });
  }, 1000);
}
componentWillUnmount() {
  clearInterval(this.interval)
}

实际上,如果你不使用interval和setTimeout,如果你的state.counter只存在于检查经过了多少秒,那将会更好。

constructor() {
  ...
  this.timeout = null
  ...
}
componentWillMount() {
  $.ajax({
    url: this.props.api,
    datatype: 'json',
    cache: false,
    success: (data) => {
      this.setState({ data })
      clearTimeout(this.timeout);
    }
  });
  this.timeout = setTimeout(() => {
    clearTimeout(this.timeout);
    location.reload();
  }, 1000 * 10);
}
componentWillUnmount() {
  clearTimeout(this.timeout)
}

setInterval开销很大。不要用它来做这种工作。