0

Trying to follow a simple clock/countdown tutorial in React:

constructor(props) {
    super(props);
    this.state = {
      secondsRemaining: 10
    };
  }

  componentDidMount(){
    let interval = setInterval(this.timer, 1000);
    this.setState({ secondsRemaining: this.state.secondsRemaining })
    this.setState({ interval: interval });
  };

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

  timer(){
    this.setState({ secondsRemaining: this.state.secondsRemaining -1 });
  };

Very obvious what everything does but when I run it, I get an error saying cannot read property secondsRemaining of undefined in the timer function

It is probably something stupid I have missed out but I just cannot see it

followed the answer to this question: setInterval in a React app

Community
  • 1
  • 1
The worm
  • 5,580
  • 14
  • 36
  • 49

4 Answers4

1

The myfunction.bind() method specifies what this will be refering to inside the method when its being called. To be sure that when you call this.timer() you are actually refering to your components state and not the object thats invoking it you will have to pass this.timer.bind(this).

ThatBrianDude
  • 2,952
  • 3
  • 16
  • 42
0

Because setInterval will call this.timer and this will be window object. you can use closure:

componentDidMount(){
   let currentInstance = this;
   let interval = setInterval(function(){ currentInstance.timer(); }, 1000);
   ...
};

at the moment of executing method componentDidMount it context with initialized property state, save into variable currentInstance. Then we closure value of currentInstance into setInterval first argument.

0

Define timer as an Arrow Function.

  timer() => this.setState({ secondsRemaining: this.state.secondsRemaining -1 })

OR

.bind your method inside constructor:

constructor(props) {
    super(props);
    this.state = {
      secondsRemaining: 10
    };
    this.timer = this.timer.bind(this);
}

I don't recommend this.timer.bind(this) inside render; because doing that, .bind will create a new function on every render.

yadhu
  • 15,423
  • 7
  • 32
  • 49
0

Because of your bounding context. You can use an arrow function or this.timer.bind(this)

ibsukru
  • 11
  • 2