Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/402.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript setInterval计时器在ReactJS的render()中工作不正常_Javascript_Jquery_Reactjs_Timer - Fatal编程技术网

Javascript setInterval计时器在ReactJS的render()中工作不正常

Javascript setInterval计时器在ReactJS的render()中工作不正常,javascript,jquery,reactjs,timer,Javascript,Jquery,Reactjs,Timer,我在React组件中有一个倒计时计时器,它会计时10秒。如果在这10秒内组件接收到后端数据,计时器将停止。否则,它将倒计时到0,此时页面将刷新,然后再次倒计时,以此类推,直到收到数据为止。我的代码如下: constructor() { ... this.counter = 10; ... } render() { const interval = setInterval(() => { const result = this.state.d

我在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,然后停止,直到数据最终加载。页面也变得非常慢。

我不知道为什么会发生这种情况,但我确信您的代码有点奇怪

  • 首先,将间隔保持在
    状态是非常奇怪的。相反,请将其保存在组件实例中,以便轻松清除

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

  • 在部件报废之前,始终清除间隔

  • 这就是我的建议

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

    时间间隔很贵。不要将其用于此类工作。

    我建议您阅读本文。您正在寻找componentWillMount和componentWillMount。是否将代码放入render()函数以确保不会启动大量新的间隔计时器?我不熟悉reactjs,但通常每秒调用render()多次。@AntonBanchev。我正在尝试在componentWillMount和componentWillMount中使用它们,正如Jesús Quintana所说的谢谢!成功了。实际上,我使用了你的第一个解决方案,因为我需要显示计数器值,因为它每秒钟递减一次。但我也理解你的第二个解决方案。我以前没有将setInterval与React一起使用过,因此从您的解决方案中学习
    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)
    }