Reference to this keyword in React callbacks

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.

This is not React-specific behavior; it is a part of how functions work in JavaScript. Generally, if you refer to a method without () after it, such as onClick={this.handleClick}, you should bind that method.

Solution 1 to fix reference to this keyword

Notice the ".bind(this)" syntax.


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>

    );

  }

}



ReactDOM.render(

  <Toggle />,

  document.getElementById('root')

);

Solution 2 to fix reference to this keyword

Notice the "handleClick = () => {" syntax. You can use this experimental public class fields syntax to correctly bind callbacks.


class Toggle extends React.Component {

  constructor(props) {

    super(props);

    this.state = {isToggleOn: true};

  }



  // This syntax ensures `this` is bound within handleClick.

  // Warning: this is *experimental* syntax.

  handleClick = () => {

    this.setState(prevState => ({

      isToggleOn: !prevState.isToggleOn

    }));

  }



  render() {

    return (

      <button onClick={this.handleClick}>

        {this.state.isToggleOn ? 'ON' : 'OFF'}

      </button>

    );

  }

}



ReactDOM.render(

  <Toggle />,

  document.getElementById('root')

);

Solution 3 to fix reference to this keyword

Notice the "onClick={() => this.handleClick()}" syntax.

The problem with this syntax is that a different callback is created each time the LoggingButton renders. In most cases, this is fine. However, if this callback is passed as a prop to lower components, those components might do an extra re-rendering. We generally recommend binding in the constructor or using the class fields syntax, to avoid this sort of performance problem.


class Toggle extends React.Component {

  constructor(props) {

    super(props);

    this.state = {isToggleOn: true};

  }



  handleClick() {

    this.setState(prevState => ({

      isToggleOn: !prevState.isToggleOn

    }));

  }



  render() {

    // This syntax ensures `this` is bound within handleClick

    return (

      <button onClick={() => this.handleClick()}>

        {this.state.isToggleOn ? 'ON' : 'OFF'}

      </button>

    );

  }

}



ReactDOM.render(

  <Toggle />,

  document.getElementById('root')

);

Leave a Comment