vanpeta
vanpeta

Reputation: 13

React: implementing timer, state property undefined inside setState while method being bind on Constructor

I'm trying to implement a simple timer component in React that starts running on props update. Everything works but the timer. • Props are being received and processed properly. • Initial "seconds" property of the state is being defined in the constructor.

But this.state is undefined inside this.setState being called from componentDidMount with the asynchronous method setInterval to run the timer.

I also tried binding the startTimer method to this in the constructor but it throws the same error. this.startTimer = this.startTimer.bind(this);

Here is the component & thank you in advance:

import React, { Component } from 'react';
import { connect } from "react-redux";

class Timer extends Component {
    constructor(props) {
        super(props);
        this.state = { seconds: 0 }
        this.intervalHandle;
    }

//Component receives this.props.started === true properly
    componentDidMount() {
        if (this.props.started) {
            this.startTimer();
        }
    }
//startTimer triggers correctly logging "STARTING" 
    startTimer() {
        console.log("STARTING")
        this.intervalHandle = setInterval(
            this.tick, 1000);
    }
//tick also triggers correctly logging "Ticking" every 1000ms
    tick() {
        console.log("TICKING")
//HERE IS THE ERROR: Uncaught TypeError: Cannot read property
//'seconds' of undefined, the console throws it once a seconds
        this.setState({ seconds: this.state.seconds + 1 })
    }
    componentWillUnmount() {
        if (!this.props.started) {
            clearInterval(this.intervalHandle);
        }
    }
// Component initialy renders
    render() {
        return <span>:0{this.state.seconds}</span>
    }
}
function mapStateToProps(state) {
    return {
        started: state.isStarted
    }
}
export default connect(mapStateToProps)(Timer);

Upvotes: 0

Views: 815

Answers (1)

Hemadri Dasari
Hemadri Dasari

Reputation: 34004

The reason it is undefined because this.tick is a function and you are not binding it.

Change it to

 this.intervalHandle = setInterval(this.tick.bind(this), 1000);

or bind it in constructor

 constructor(props){
       super(props);
       this.tick = this.tick.bind(this);
  }

 this.intervalHandle = setInterval(this.tick, 1000);

or use arrow function

 this.intervalHandle = setInterval(() => this.tick(), 1000);

 tick = () => {
    console.log("TICKING")
    this.setState({ seconds: this.state.seconds + 1 })
}

Both the changes should resolve your issue

Upvotes: 2

Related Questions