3

I wanted to understand the basic difference between how the below syntax works.

// Syntax 1
class Component extends React.Component {
  constructor(props) {
    super(props)
    this.handleClick = this.handleClick.bind(this)
  }

  handleClick() {
    // ...
  }
}

// Syntax 2

handleClick = () => {
  console.log('this is:', this)
}
<button onClick={this.handleClick}>
  {'Click me'}
</button>

While syntax 1 needs an explicit binding to be specified inside constructor. However, it seems like with syntax 2, that is not needed. How is syntax 2 able to achieve the binding automatically ?

I assume this understanding/syntax can be extended for any framework including React, Angular, Ember, etc

copenndthagen
  • 49,230
  • 102
  • 290
  • 442
  • In syntax 1, you're using a normal function, then explicitly calling `.bind()`. In syntax 2, you're using an arrow function, which automatically does the binding for you, so you don't have to call .bind(). – Scotty Jamison Dec 09 '20 at 05:20

1 Answers1

1

Class fields - that is, properties defined directly inside the class body - are essentially just syntax sugar for the same thing inside the constructor. So, this:

class Something {
  handleClick = () => {
    console.log('this is:', this)
  }
}

is, desugared:

class Something {
  constructor() {
    this.handleClick = () => {
      console.log('this is:', this)
    };
  }
}

With the sugaring removed, it should be clear what's going on - the arrow function means that the this refers to what this is in the constructor, which is the instance itself, no binding needed.

This isn't just a React or framework thing - these are standard rules in vanilla JavaScript.

If you don't bind the method or use an arrow function or anything like that, then:

<button onClick={this.handleClick}>

fails for the same reason that

someButton.addEventListener('click', myObj.someFn)

will also fail to call someFn with a calling context of myObj - all the browser knows is to call the callback passed to the click listener; the calling context of myObj gets lost when passed like that.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • Thanks...So again when we say "class fields", are both "handleClick" as used in syntax 1/2 not class fields....as also your definition states "properties defined directly inside the class body" – copenndthagen Dec 09 '20 at 04:59
  • Indeed, in the first version, `handleClick` is not a class field, but a method on `Component.prototype`. It's not an arrow function that comes with the proper calling context built-in. – CertainPerformance Dec 09 '20 at 05:01
  • I'm not sure if the OP is ever talking about class fields in the original question. My understanding of syntax 2 was that all of that was inside a render function. – Scotty Jamison Dec 09 '20 at 05:18
  • @ScottyJamison The `handleClick = () => {` really looks like a use of a class field to me. If it weren't, I'd think it'd have a `const` in front of it. This looks to be all in a class component, not a functional component – CertainPerformance Dec 09 '20 at 05:24
  • @CertainPerformance - Regarding your example of someButton.addEventListener('click', myObj.someFn), I assume you are referring to very basic JS working...But any quick reference on that you would want to point for me to refer... – copenndthagen Dec 09 '20 at 08:25
  • @testndtv It's just how function references in callbacks work. It's not even something to do with the DOM. See here for an example: https://jsfiddle.net/juy6c32s/ – CertainPerformance Dec 09 '20 at 14:11