The worm
The worm

Reputation: 5888

Why is my state undefined?

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

Upvotes: 0

Views: 842

Answers (4)

ibsukru
ibsukru

Reputation: 11

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

Upvotes: 0

yadhu
yadhu

Reputation: 15632

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.

Upvotes: 0

ThatBrianDude
ThatBrianDude

Reputation: 3190

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

Upvotes: 1

Basim Al-Jawahery
Basim Al-Jawahery

Reputation: 181

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.

Upvotes: 0

Related Questions