1

In a React countdown timer, there is a value in state called timeLeft that should be reduced every second. In the code there is a function that attempts to achieve this called countDown(), however, it causes an error: TypeError: this.setState is not a function. Any help would be greatly appreciated.

index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import './style.css';

/*
* A simple React component
*/
const initState = {
  breakLength: 5,
  sessionLength: 25,
  init: 'session',
  timeLeft: 25
}

class Clock extends React.Component {

  constructor(props) {
    super(props);
    this.state = initState;
    this.breakDecrement = this.breakDecrement.bind(this);
    this.breakIncrement = this.breakIncrement.bind(this);
    this.sessionDecrement = this.sessionDecrement.bind(this);
    this.sessionIncrement = this.sessionIncrement.bind(this);
    this.startStop = this.startStop.bind(this);
    this.reset = this.reset.bind(this);
  }

  breakDecrement() {
    let breakLength = this.state.breakLength - 1;
    this.setState({ breakLength: breakLength });
  }
  breakIncrement() {
    let breakLength = this.state.breakLength + 1;
    this.setState({ breakLength: breakLength });
  }
  sessionDecrement() {
    let sessionLength = this.state.sessionLength - 1;
    this.setState({ sessionLength: sessionLength });
  }
  sessionIncrement() {
    let sessionLength = this.state.sessionLength + 1;
    this.setState({ sessionLength: sessionLength });
  }

  startStop() {
    this.countDown();
  }

  reset() {
    this.setState({ breakLength: 5 });
    this.setState({ sessionLength: 25 });
    this.setState({ init: 'session' });
    this.setState({ timeLeft: 25 });
  }

  countDown(){
    setInterval(down, 1000);
    let minus = this.state.timeLeft - 1;
    function down(minus)
    {
      this.setState({ timeLeft: minus });
    }
  }


  render() {
    return (
      <div id="clock">
      <h1 id="title">25-5 Clock</h1>

      <div>
      <p id="break-label">Break Length</p>
      <p id="break-length">{this.state.breakLength}</p>
      <button id="break-decrement" onClick={e => this.breakDecrement()}> Decrease </button>
      <button id="break-increment" onClick={e => this.breakIncrement()}> Increase </button>
      </div>

      <div>
      <p id="session-label">Session Length</p>
      <p id="session-length">{this.state.sessionLength}</p>
      <button id="session-decrement" onClick={e => this.sessionDecrement()}> Decrease </button>
      <button id="session-increment" onClick={e => this.sessionIncrement()}> Increase </button>
      </div>

      <hr/>

      <div>
      <p id="timer-label">{this.state.init}</p>
      <p id="time-left">{this.state.timeLeft}</p>
      <button id="start_stop" onClick={e => this.startStop()}> start/stop </button>
      <button id="reset" onClick={e => this.reset()}> reset </button>
      </div>

      </div>
    );
  }
};

/*
* Render the above component into the div#app
*/
ReactDOM.render(<Clock />, document.getElementById("app"));

index.html

<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
  <meta charset="utf-8">
  <title>25-5 Clock</title>
  <style>
  </style>
</head>
<body>
  <main>
    <div id="app"></app>
    </main>
  </body>
  </html>
65535
  • 523
  • 1
  • 10
  • 32
  • 1
    You need to use an arrow function instead so you don't lose the `this` context. –  Sep 22 '20 at 18:50
  • Does this answer your question? [React this.setState is not a function](https://stackoverflow.com/questions/31045716/react-this-setstate-is-not-a-function) –  Sep 22 '20 at 18:54
  • This question gets asked all the time and has lots of existing answers; refer to the 2nd answer of the duplicate (also note that you need to set `minus` inside the timeout callback) –  Sep 22 '20 at 18:54
  • I already marked it as a duplicate. Duplicates aren't supposed to be answered, because they don't add anything worthwhile to the site, they just create clutter and redundancy. –  Sep 22 '20 at 19:54
  • It doesn't have to be an exact duplicate; like I said the [2nd answer](https://stackoverflow.com/a/35020509/5734311) is the one you should be looking at. But sure, one of [these](https://www.google.com/search?q=this.setstate+is+not+a+function+site%3Astackoverflow.com&oq=this.setstate+is+not+a+function+site%3Astackoverflow.com) might be an even better fit. –  Sep 22 '20 at 21:13
  • Here's the reference duplicate: https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback There's no point in arguing over this; just try googling errors first before opening a question. –  Sep 22 '20 at 21:18

1 Answers1

1

The literal context of function 'down' is not bind this. You should use arrow function call:

 countDown(){
    const down = (minus) =>
    {
        this.setState({ timeLeft: minus });
    }

    setInterval(() => down(this.state.timeLeft - 1), 1000);
 }
Viet Dinh
  • 1,871
  • 1
  • 6
  • 18
  • Please don't answer dupes, especially not after they are already marked as dupes. –  Sep 22 '20 at 19:56