/* Code-Comments */

Aha Moments With Classes - Part Deux

November 11, 2019

Recently I wrote about my aha realization of what exactly we’re doing when we pass the props that a class constructor receives to super.

In the same vein, today I realized what it means to actually bind a function to a class within the constructor / why it works.

First, what am I talking about?

Imagine a simple React class component that renders a number and a button. The button has a click handler which is supposed to increase the value by 1 on each click:

class MyComponent extends React.Component {
  constructor(props) {
    super(props)
    this.state = { val: undefined }
  }

  handleClick() {
    const { value } = this.state
    this.setState({ value: value + 1 })
  }

  render() {
    const { value } = this.state
    return (
      <>
        <div>Value: {value}</div>
        <button onClick={this.handleClick}>Increment</button>
      </>
    )
  }
}

The problem is that within the handleClick method right now, this is not the class.

Two ways to solve it:

  1. Bind the function to the class to persist the context
  2. Convert the function to an arrow function to take advantage of the runtime context

Bind The Function

Binding functions is the original way to address the problem that the handleClick has a own execution context.

The problem is then that the this referred to within handleClick is not the this of the class and therefore has no concept of the variable state

To remedy this we can bind it to the class constructor:

class MyComponent extends React.Component {
  constructor(props) {
    super(props)
    this.state = { val: undefined }
    this.handleClick = this.handClick.bind(this)
  }

  handleClick() {
    /* ... */
  }
  /* ... */
}

The reason this works is that the this inside of the bind (and actually the one to the left of the handleClicks as well) is the context of the the class constructor which is aware of the state property.

Said another way: the this in the constructor is the class while the this within the handleClick is the function.

Arrow Functions

Arrow functions make the binding of functions to the class unnecessary because arrow functions take on the this of the enclosing lexical scope.1

Because of that, assign an anonymous (or named) arrow function to the variable handleClick and you will not need to bind at all:

class MyComponent extends React.Component {
  constructor(props) {
    super(props)
    this.state = { val: undefined }
  }

  handleClick = () => {
    /* ... */
  }
  /* ... */
}

In Summary

With arrow functions (function expressions), this is defined when it’s written whereas with a function declaration, this is defined at time of execution, though we can explicitly set the this value through .bind.

Footnotes & Additional Reading


Stephen Weiss

Thanks for reading! My name's Stephen Weiss. I live in Chicago with my wife, Kate, and dog, Finn.
Click here to see the archives of my weeks in review and sign up yourself!