0

I was running into a big problem where there was a function that did not have access to the props of the component in react:

renderRow(employee) {
    console.log('props here', this.props); //undefined
}

But when I changed it to a fat arrow function it works fine

renderRow = (employee) => {
   console.log('props here', this.props); //success?
}

Why is this? What am I not understanding?

Z2VvZ3Vp
  • 5,098
  • 6
  • 18
  • 32
  • 1
    you need to add `renderRow = this.renderRow.bind(this)` inside your component constructor. – Umesh Jan 10 '18 at 04:00
  • 1
    Looks like `renderRow` is called from a different context. The implicit variable `this` always refers to the current context in which the function executes. To make sure you point to the correct this one needs to either use `arrow` function that binds the method to the instance of the class or use `.bind` at the appropriate place binding it with correct `this`. – Panther Jan 10 '18 at 04:02
  • This must be a method you are using as an event handler. If so, you're putting the method out of context. Vanilla JSs `addEventListener` and its problem with context works the same way. – Andrew Jan 10 '18 at 04:31
  • `this` inside your function and `this` inside arrow function has different scope, i suggest you to use arrow function whenever possible – rudydydy Jan 10 '18 at 04:54
  • Traditionally, the value of `this` primarily depends on who's calling the function. Here is one of the better explanations of `this` keyword in JS: https://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work/3127440#3127440 – Umur Kontacı Jan 10 '18 at 05:20

4 Answers4

2

For the benefit of the discussion. Let's say that your first function is a normal function and your second function is an arrow function

First of all, let's understand that for each normal function execution in JS, the JS engine creates it's own execution context. A new "this" is then created for each these execution context and thus belong to that function.

Now as it relates to your case, the this keyword on your first function

renderRow(employee) {
    console.log('props here', this.props); //undefined
}

refers itself (or to the function where it's currently being called), because the JS engine has created a new this object that refers to it. Thus when your program runs, this.props will have the value of undefined because it wasn't defined on the current execution context (which again, is your renderRow function)

On the other hand... the JS engine doesn't create a new this for arrow functions. To put it simply, an arrow function doesn't have it's own this and thus on your second example,

renderRow = (employee) => {
   console.log('props here', this.props); //success!!!
}

this refers to the outer execution context (which is your React Component) and so now this.props work.

For more information about the topics, you can check on these resources...

THIS - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this

ARROW FUNCTIONS - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

Hope this helps :)

balfonso
  • 581
  • 1
  • 7
  • 16
0

In your first example, this has another scope.

employee is the scope in your second example, which is why this references to employee there

Patrick M
  • 113
  • 2
  • 7
0

The fat arrow function works because this in arrow function doesn't rebind which helps keep it context and doesn't change on run time.

While this in vanilla always refer to the outer scope, to use this on vanilla function you have to bind it to the employee function using the .bind() method

devamaz
  • 75
  • 1
  • 7
0

Arrow functions make our code more concise, and simplify function scoping and the this keyword.

Example:

    // ES5
    API.prototype.get = function(resource) {


   var self = this;
    return new Promise(function(resolve, reject) {
        http.get(self.uri + resource, function(data) {
            resolve(data);
          });
    });
};

// ES6
API.prototype.get = function(resource) {
    return new Promise((resolve, reject) => {
        http.get(this.uri + resource, function(data) {
            resolve(data);
         });
       });
};

for more detail check here

yogesh agrawal
  • 590
  • 6
  • 14