Search code examples
javascriptreactjssettimeoutstate

setInterval in a React app


I'm still fairly new at React, but I've been grinding along slowly and I've encountered something I'm stuck on.

I am trying to build a "timer" component in React, and to be honest I don't know if I'm doing this right (or efficiently). In my code below, I set the state to return an object { currentCount: 10 } and have been toying with componentDidMount, componentWillUnmount, and render and I can only get the state to "count down" from 10 to 9.

Two-part question: What am I getting wrong? And, is there a more efficient way of going about using setTimeout (rather than using componentDidMount & componentWillUnmount)?

Thank you in advance.

import React from 'react';

var Clock = React.createClass({

  getInitialState: function() {
    return { currentCount: 10 };
  },

  componentDidMount: function() {
    this.countdown = setInterval(this.timer, 1000);
  },

  componentWillUnmount: function() {
    clearInterval(this.countdown);
  },

  timer: function() {
    this.setState({ currentCount: 10 });
  },

  render: function() {
    var displayCount = this.state.currentCount--;
    return (
      <section>
        {displayCount}
      </section>
    );
  }

});

module.exports = Clock;

Solution

  • I see 4 issues with your code:

    • In your timer method you are always setting your current count to 10
    • You try to update the state in render method
    • You do not use setState method to actually change the state
    • You are not storing your intervalId in the state

    Let's try to fix that:

    componentDidMount: function() {
       var intervalId = setInterval(this.timer, 1000);
       // store intervalId in the state so it can be accessed later:
       this.setState({intervalId: intervalId});
    },
    
    componentWillUnmount: function() {
       // use intervalId from the state to clear the interval
       clearInterval(this.state.intervalId);
    },
    
    timer: function() {
       // setState method is used to update the state
       this.setState({ currentCount: this.state.currentCount -1 });
    },
    
    render: function() {
        // You do not need to decrease the value here
        return (
          <section>
           {this.state.currentCount}
          </section>
        );
    }
    

    This would result in a timer that decreases from 10 to -N. If you want timer that decreases to 0, you can use slightly modified version:

    timer: function() {
       var newCount = this.state.currentCount - 1;
       if(newCount >= 0) { 
           this.setState({ currentCount: newCount });
       } else {
           clearInterval(this.state.intervalId);
       }
    },