0

I am new to React. I encountered a strange problem while I am following the "Quick Start" of React official page https://facebook.github.io/react/docs/state-and-lifecycle.html . You can try on CodePen here: http://codepen.io/gaearon/pen/amqdNA?editors=0010

In this code snippet

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

it uses arrow function syntax to define a function which would be executed repeatedly, by passing the anonymous function object as the first argument of setInterval().

Since I am a curious guy, I tried several different ways to pass an "equivalent" function object as the first argument. But none of my ways works.

componentDidMount() {
    this.timerID = setInterval(
        this.tick, // This cannot work in CodePen

        //function () {
            //this.tick();
        //}, // No

        //function () {
            //return this.tick();
        //}, // No

        //() => this.tick(), // This is the official way that works
        //() => {this.tick();}, // This also works, but notice the difference between this and the last one 
        //() => {this.tick()}, // Also works
        //() => {return this.tick();}, // Also works, think it equivalent as official one
        1000
    );
}

I think in a pure Javascript code snippet, all these ways are valid for setInterval to work. Especially, as the official document (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions) says, the arrow function definition is generally equivalent to the function () { ... } definition. But they just seem not equivalent in React and Babel.

After I examined the compiled Javascript code by Babel, they differ by a _this2 object.

// Javascript compiled by Babel
Clock.prototype.componentDidMount = function componentDidMount() {
    var _this2 = this;

    this.timerID = setInterval(
        //this.tick // This is the compiled code using one of my way

        /*function () {
            this.tick();
        },*/ // This is another one

        function () {
            return _this2.tick();
        }, // This is the compiled code using the official way

        //function () {
            //_this2.tick();
        //}, // This is the compiled code of another working example
        1000
    );
};

So, I am asking, why must we use the arrow function syntax here? Why the equivalent ways does not get compiled correctly? Is this a bug of React or Babel?

EDIT:

OK. Thank you very much, guys! That tricky thing about "this" in Javascript almost answers every question I have. Now I know there is a big difference between () => {} definition and function () {} definition, and why Babel doesn't do what I expect.

But, this does not answer why this could not work

this.timerID = setInterval(
    this.tick, // This cannot work in CodePen
    1000
);

Could someone also take a look on this "easy" line of code? I guess it's not related to "this" in the same way?

  • 1
    Funktion(){} and ()=>{} are Not the same thing. The arrow function will keep its sourrounding context (this) and the normal function is declaring a new context for "this" – cyr_x Feb 01 '17 at 21:55
  • @cyrix Ah! This is really important! – jlwangPoincare Feb 01 '17 at 22:07
  • http://stackoverflow.com/a/41970338/2902660 provides a little description how the _**context**_ of a function (i.e. the value of `this` inside it's function definition) is evaluated – Pineda Feb 01 '17 at 23:00

1 Answers1

1

Function () {} and () =>{} are NOT the same thing.

Consider:

#1
function foo() { 
  console.log('foo');
}

vs:
#2
foo = () => { 
  console.log('foo')
}

Function #1 has a newly created context confined to the function, whereas function #2 doesn't create a new context this variable.

When Babel converts everything, I believe in order for function #2 to not have a new context it does something like this:

foo = () => {
  console.log(this.data);
}

Becomes

var this_2 = this;
function foo () {
  console.log(this_2.data);
}
Turtle
  • 1,369
  • 1
  • 17
  • 32