javascript - setInterval timer not working properly in render() of ReactJS - Stack Overflow

I have a countdown timer in a React ponent, which counts for 10 seconds. If within those 10 seconds the

I have a countdown timer in a React ponent, which counts for 10 seconds. If within those 10 seconds the ponent receives backend data, the timer is stopped. If not, it will count down to 0, at which point the page will refreshed, and count down again, and so on, until the data is received. My code is given below:

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

The problem is, the timer does not appear to decrement every second. Instead, the behavior is erratic - from 10 to maybe 7 it is very fast, then it may hang or even go on after 0, i.e. negative. The page is reloading all right. Is this code wrong, or is it a problem related to React's state? Any help would be great!

UPDATE:

I changed the code to this:

constructor() {
    this.state = {
        ...
        interval: '',
        counter: 10
    };
}

ponentWillMount() {
    $.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 });
}

ponentWillUnmount() {
    clearInterval(this.state.interval);  
}

It is better than before in that the timer works properly the first time - it goes from 10 to 0 every 1 second. However, when even after 10 seconds the data has not loaded and the timer starts from 10 again, it reaches 9 and then stops, until the data finally loads. The page also bees very slow.

I have a countdown timer in a React ponent, which counts for 10 seconds. If within those 10 seconds the ponent receives backend data, the timer is stopped. If not, it will count down to 0, at which point the page will refreshed, and count down again, and so on, until the data is received. My code is given below:

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

The problem is, the timer does not appear to decrement every second. Instead, the behavior is erratic - from 10 to maybe 7 it is very fast, then it may hang or even go on after 0, i.e. negative. The page is reloading all right. Is this code wrong, or is it a problem related to React's state? Any help would be great!

UPDATE:

I changed the code to this:

constructor() {
    this.state = {
        ...
        interval: '',
        counter: 10
    };
}

ponentWillMount() {
    $.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 });
}

ponentWillUnmount() {
    clearInterval(this.state.interval);  
}

It is better than before in that the timer works properly the first time - it goes from 10 to 0 every 1 second. However, when even after 10 seconds the data has not loaded and the timer starts from 10 again, it reaches 9 and then stops, until the data finally loads. The page also bees very slow.

Share Improve this question edited Aug 30, 2016 at 14:56 user3033194 asked Aug 30, 2016 at 13:42 user3033194user3033194 1,8297 gold badges44 silver badges66 bronze badges 3
  • I remend you read this facebook.github.io/react/docs/ponent-specs.html you are looking for ponentWillMount and ponentWillUnmount – Jesús Quintana Commented Aug 30, 2016 at 13:46
  • Are you sure that you are not starting numerous new interval timers by putting the code in the render() function? I am not familiar with reactjs, however usually render() gets called multiple times per second. – Anton Banchev Commented Aug 30, 2016 at 13:55
  • @AntonBanchev Possibly. I am trying to use them in ponentWillMount and ponentWillUnmount now, as Jesús Quintana said – user3033194 Commented Aug 30, 2016 at 13:57
Add a ment  | 

1 Answer 1

Reset to default 3

I'm not sure why this is happening but I'm sure your code is somewhat very strange.

  1. First of all, keeping your interval to state is very strange. Instead, keep it in your ponent instance so that you can clear it easily

  2. Do not set data and check it with interval. You can release interval when your api request is done and set data to state.

  3. Always clear interval before ponent is dismissed.

This is what I can suggest.

constructor() {
  ...
  this.interval = null
  this.state = { counter: 10 }
  ...
}

ponentWillMount() {
  $.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);
}

ponentWillUnmount() {
  clearInterval(this.interval)
}

actually if you don't use interval and setTimeout it would be much better if your state.counter exists only to check how many second has passed.

constructor() {
  ...
  this.timeout = null
  ...
}

ponentWillMount() {
  $.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);
}

ponentWillUnmount() {
  clearTimeout(this.timeout)
}

setInterval is expensive. Don't use it for this kind of work.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744786735a4593672.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信