0

In this example here, we need to bind the 'this' object of handleClick() to the global scope:

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // This binding is necessary to make `this` work in the callback
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

However, handleClick() is defined in the scope of the component, so shouldn't we not need to specify the 'this' object for this function, as it will already refer to the component itself?

  • 1
    because of what `this` is in an event handler (often the object that dispatched the event - in your code, it'd be the `button` element) – Jaromanda X Oct 21 '17 at 02:01
  • also, your code would result in `isToggleOn` being `true` initially, then either `'ON'` or `'OFF'` - so, always "truthy" - seems odd – Jaromanda X Oct 21 '17 at 02:03
  • You have to be careful about the meaning of this in JSX callbacks. In JavaScript, class methods are not bound by default. If you forget to bind this.handleClick and pass it to onClick, this will be undefined when the function is actually called. – Louis Huang May 11 '22 at 10:24
  • ES5 introduced the bind() method to set the value of a function's this regardless of how it's called – Louis Huang May 11 '22 at 10:28
  • In strict mode, if the value of this is not set when entering an execution context, it remains as undefined. – Louis Huang May 11 '22 at 10:37

1 Answers1

2

You are correct, but you're missing one thing. The scope of this without binding to the handler IS the component. So what happens when you want the context of the event? You don't have it.

Another way to solve this is to lexically bind the component, so that you don't have to worry about manually binding each and every function.

handleClick = () => { //arrow function applied
    this.setState(prevState => ({
        isToggleOn: !prevState.isToggleOn
    }));
}

Note that now you don't need a component constructor here now anymore as well.

constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // This binding is necessary to make `this` work in the callback
    this.handleClick = this.handleClick.bind(this);
}

Now becomes

state = {isToggleOn: true};
Sterling Archer
  • 22,070
  • 18
  • 81
  • 118