0

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);
2
  • You need to bind tick() in the constructor, that's where it's trying to access this.state. Commented Aug 17, 2018 at 0:38
  • @Jayce444, thank you. That solves the issue. Commented Aug 17, 2018 at 0:57

1 Answer 1

2

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

Sign up to request clarification or add additional context in comments.

1 Comment

thank you!!! Hemadri Dasari, you are totally right. Both solutions work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.