0

I'm trying to work out how to do a pre-game countdown in a Game component in React. I'm trying like this, but it's saying that this.countDown isn't a function - when it's clearly defined.

Can someone point out where I'm going wrong?

class Game extends Component {
  constructor() {
    super();

    this.state = {
      timer: 5,
      isHidden: true,
      randomIndex: 0,
      score: 0
    };

    this.countDown = this.countDown.bind(this);
  }

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

  render() {
    const tables = this.props.tables.map(table => {
      return (
        <li key={table.uniqueId}>
          {table.timesTable[0]} X {table.timesTable[1]}
        </li>
      );
    });

    setInterval(function() {
      this.countDown();
      console.log(this.state.timer);
    }, 1000);

    // if (this.state.timer > 0) {
    //     this.countDown();
    // }

    return (
      <div className="Game">
        <h3>Current Tables are:</h3>
        {tables}
        <h1 id="countdown">{this.state.timer}</h1>
        <Question />
        {/* question handles the right or wrong logic, receives a random timestable */}
        <h3>Score: {this.state.score}</h3>
        <button onClick={this.stopGame}>Stop Game</button>
        <button onClick={this.startOver}>Start Over</button>
      </div>
    );
  }
}

export default Game;
3
  • 1
    Inside setInterval use arrow function or bind this, this is not accessible in callbacks in case of normal functions Commented Aug 9, 2018 at 14:53
  • 1
    Brilliant thank you - I thought it was some sort of scoping error. I'm guessing my this was referring to the setInterval? Commented Aug 9, 2018 at 14:59
  • Ya actually in normal functions ( non arrow or without binding this ) this points to object from where it is called and as setInterval takes it as callback, so it won't be called from your object Commented Aug 9, 2018 at 15:06

1 Answer 1

3

In that example, this in setInterval's callback refers to the global window object, since it's executed as window.setInterval(...), so this.countDown() would be equal to window.countDown(), which is obviously incorrect.

To get this from parent's scope, you could use arrow functions.

setInterval(() => {
  this.countDown();
  console.log(this.state.timer)
}, 1000);

or simply bind this:

setInterval(function() {
  this.countDown();
  console.log(this.state.timer)
}.bind(this), 1000); // bind this from parent's scope
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.