-2

I'm currently trying to do the React tutorial at https://en.reactjs.org/docs/state-and-lifecycle.html. In the code there is the following block with an arrow function.

https://codepen.io/gaearon/pen/zKRqNB?editors=0010

componentDidMount() {
 this.timerID = setInterval(
   () => this.tick(),
   1000
 );
}

As a beginner, I have little experience with Arrow functions and don't quite understand when it makes sense to use them, so I would like to write it as a normal function. So I changed my code as follows:

componentDidMount() {
  this.timerID = setInterval (
    function() {
      this.tick();
    },
    1000
  );
}

However, then the code no longer works. Can someone help me please? Where is the mistake?

  • 1
    Take a look at https://stackoverflow.com/questions/48699573/correct-use-of-arrow-functions-in-react – Anurag Srivastava May 21 '21 at 16:21
  • 2
    the way arrow functions work is; they take on the scope of their surroundings. in this case, with the arrow function, 'this' refers to the component instance. When you define the arrow function as a regular function, 'this' refers to the function, not the parent component instance, so `this.tick()` will not be present. you will need to make the function a method on the class and bind it in the constructor for it to work. you also have the issue of the function being called after a timeout – Abdul Ahmad May 21 '21 at 16:22

2 Answers2

4

That's because arrow functions do not change this, while regular functions do. That's what's causing the difference for you. Here are some options:

componentDidMount() {
  const that = this;
  this.timerID = setInterval (
    function() {
      that.tick();
    },
    1000
  );
}

or

componentDidMount() {
  this.timerID = setInterval(this.tick, 1000);
}
Christian Fritz
  • 20,641
  • 3
  • 42
  • 71
  • small nitpick for more clarity: instead of 'that' I'd use 'self' or 'component' or 'instance', but yes, agreed with your options. For more completeness, another option (assuming the function passed to the callback does more things), we can define the timeout function callback as a method in the class that's bound in the construtor – Abdul Ahmad May 21 '21 at 16:26
  • I tried it with your 2nd example but I still get an error. Why? Here is the code example from the tutorial. https://codepen.io/gaearon/pen/vXdGmd?editors=0010 – Franziska721 May 21 '21 at 16:29
  • this.tick needs to be bound in the constructor; `this.tick = this.tick.bind(this)` because it runs after a timeout – Abdul Ahmad May 21 '21 at 16:30
0

in addition to what Christian mentioned above, you need to keep in mind that async code (code in timeouts, click event handlers, after API requests, promises, etc...) needs to be bound to the scope of the instance. So with the second example he gave you, you would need to do this:

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

  componentDidMount() {
    this.timerID = setInterval(this.tick, 1000);
  }

  tick() { ... }
}
Abdul Ahmad
  • 9,673
  • 16
  • 64
  • 127
  • Great! This works for me thank you! Do you know a good tutorial where these constructor bindings are explained in detail and in which cases I should do this in practice? Is this best practice or should I better do it with arrow functions like in the example? – Franziska721 May 21 '21 at 16:47