React.js Passing Functions to Components: Bind vs no-Binds

class App extends React.Component {
  constructor() {
    super();
    this.name = "Bob";
    this.handleClickTwo = this.handleClickOne.bind(this);
  }
  
  handleClickOne() {
    alert(this.name);
  }
  
  handleClickThree = () => alert(this.name);
  
  render() {
    return (
      <div>
        <button onClick={ this.handleClickOne }> Click One </button>
        <button onClick={ this.handleClickTwo }> Click Two </button>
        <button onClick={ this.handleClickThree }> Click Three </button>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="app"></div>

I’m trying to understand React.js more, and I wanted to test out some things. Clicking buttons with the label “Click Two” and “Click Three” work as intended meaning it shows an alert for the name “Bob”.

But when I click the button labelled “Click One”, it gives me an error saying that ‘name’ is an undefined property.

Am I misunderstanding React.js or JS in general? Does the ‘this’ in handleClickOne() refer to the function itself and not what’s in the constructor? And if so, why does handeClickTwo work?

Answer

functions are not bound by default in javascript. You didn’t bind handleClickOne, so you can’t call this.handleClickOne

handleClickTwo is bound in your code in the constructor, using this.handleClickTwo = this.handleClickOne.bind(this).

handleClickThree uses public class fields syntax to correctly bind the callback, so it works as well.

To bind handleClickOne, you must use this.handleClickOne = this.handleClickOne.bind(this) to bind it in the constructor.

class App extends React.Component {
  constructor() {
    super();
    this.name = "Bob";
    this.handleClickOne = this.handleClickOne.bind(this);
    this.handleClickTwo = this.handleClickOne.bind(this);
  }
  
  handleClickOne() {
    alert(this.name);
  }
  
  handleClickThree = () => alert(this.name);
  
  render() {
    return (
      <div>
        <button onClick={ this.handleClickOne }> Click One </button>
        <button onClick={ this.handleClickTwo }> Click Two </button>
        <button onClick={ this.handleClickThree }> Click Three </button>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="app"></div>