Jeff Frazier
Jeff Frazier

Reputation: 579

Using setInterval in Meteor with React

I'm trying to understand how to use setInterval or similar in Meteor with React for a timer. I have a child component that has an hourly start and end time, and uses moment.js to get the current time. If the current time is between the start and end time, I show a progress bar.

I'm using the react-timer-mixin, and right now my component looks like this.

Driver = React.createClass({
  mixins: [TimerMixin],
  componentDidMount: function(){
    // componentDidMount is called by react when the component
    // has been rendered on the page. We can set the interval here:
    this.setInterval(this.currentTime, 15000);
  },

  currentTime: function() {
    //  Get the start time.
    var beginTime = moment(this.props.driver.startTime,"hh:mm");
    // Add an hour for end time.
    var endTime = moment(beginTime).add(1,'hours');
    // Get the current time.
    var now = moment();
    // Get total minutes between start and end.
    totalMin = endTime.diff(beginTime);
    // Get elapsed minutes.
    currMin = now.diff(beginTime);
    // Determine where we are in the schedule.
    if (moment(now).isBetween(beginTime, endTime)) {
      progress = Math.round((currMin / totalMin) * 60, -1);
      console.log(progress);
      return progress;
    }
    else {
      // Show this schedule as done.
      return 60
    }
  }, 

  // A bunch of other functions

  render() {
    return (
      <DriverBar current={this.currentTime()} total="60" />
    );
  }
});

I'm certain the currentTime function is running within setInterval, because progress is updated every 15 seconds in the browser console log, since I have that in my function at the moment. However, I cannot get the updated progress value in my component. It shows the initial progress value, but doesn't update with setInterval. Am I just calling the wrong thing in the <DriverBar />?

Also, if this is not the React or Meteor way to do this, by all means I am not stuck to it and would appreciate direction.

Upvotes: 4

Views: 771

Answers (2)

Jeff Frazier
Jeff Frazier

Reputation: 579

The answer for this type of scenario is to use state. Many thanks to Ramsay Lanier for the help.

Driver = React.createClass({
  mixins: [TimerMixin],
  getInitialState: function() {
    return {progress: 0};
  },

  componentDidMount() {
    this.setInterval(this.currentTime, 1000);
  },

  currentTime: function() {
    [...]

    if (moment(now).isBetween(beginTime, endTime)) {
      progress = Math.round((currMin / totalMin) * 60, -1);
      this.setState({progress: progress});
    }
  },

render() {
  let progress = this.state.progress;

  return (
    <DriverBar current={progress} total="60" />
  );
}

Upvotes: 0

Christian Fritz
Christian Fritz

Reputation: 21364

I'm fairly certain that this is an issue with this. What this refers to can change depending on the context in which a function is called, and this is a common pitfall with setTimer. The typical solution is to use the javascript function bind to explicitly set the this context for the callback.

Try this:

this.setInterval(this.currentTime.bind(this), 15000);

Upvotes: 1

Related Questions