2019-11-11
|~3 min read
|467 words
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:
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 handleClick
s 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 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 = () => {
/* ... */
}
/* ... */
}
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
.
Hi there and thanks for reading! My name's Stephen. I live in Chicago with my wife, Kate, and dog, Finn. Want more? See about and get in touch!