What is the best way to .bind(this) in React?

Barry Michael Doyle
6 min readAug 28, 2018

--

Anyone getting started with React is bound to come across the mistake of not binding this to their event handlers. I’m sure that 90% of you reading this post have experienced that frustrating "'this' inside your Component event handler is undefined" error. The remaining 10% of you reading just aren’t React developers.

In order to illustrate potential solutions to this problem. I have created this simple component below which doesn’t have this bound yet:

import React, { Component } from 'react';export default class CounterButton extends Component {
state = { counter: 0 }
incrementCounter() {
this.setState(prevState => ({
counter: prevState.counter + 1,
}));
}
render() {
return (
<Button onClick={this.incrementCounter}>
{this.state.counter}
</Button>
);
}
}

The “this is undefined” error will occur using this code, but we’ll talk about the best way to fix it soon!

This is a component that renders a button with the counter which is defaulted to 0. Upon clicking the button, the incrementCounter event handler is meant to run. This event handler increments the value of counter in the component state. This will cause the component to re-render with the new state value. The new state value is the previous incrementCounter state value plus 1.

One last thing! Most people find it weird using this.setState(prevState => ({ counter: prevState.counter + 1 })) to update the component state. Why not just say this.setState({ counter: this.state.counter + 1 })? I shall direct you to this fantastic tweet by Dan Abramov who is one of the core ReactJS developers.

How to solve the “this is undefined” Error.

In modern React classes, there are about 4 standard ways of solving the “this is undefined” error. They all have the pros and cons which involve quickest fixes, best performance and cleanest solutions. Let’s demonstrate the different methods to solving this error and chat about the pros and cons involved with each method.

Bind in the render function: The “Quick Fix”

The ultimate quick fix solution is to .bind() in the render function like this:

...
render() {
return (
<Button onClick={this.incrementCounter.bind(this)}>
{this.state.counter}
</Button>
);
}
...

This is most certainly the quick fix solution to get your program running. Now you can carry on and stop having the pesky undefined this error. It’s also fairly clean even though it does add some logic to your render function which could clutter things as your app gets bigger.

The problem with this approach is that your component will re-render whenever it receives new props. That means that this .bind() function will be recalled each time that the component is re-rendered. The performance knock won’t really be noticeable but if you’re all about optimizing your application to the fullest, then there are better practices to follow.

Arrow Function in the render: The other “Quick Fix”

Another .bind() in render function is to use an arrow function in the render method like this:

...
render() {
return (
<Button onClick={() => this.incrementCounter()}>
{this.state.counter}
</Button>
);
}
...

This method is also a very quick fix and has the same barely noticeable performance knock that the previous method has. Some people don’t like seeing the .bind(this) function because they never really understand what it means. However, in my honest opinion it also makes your render method look a little bit cluttered.

Arrow Function in Class Property: The “Clean Fix”

The most popular method used to handle the binding issue is to use an arrow function in your class property like this:

...
export default class CounterButton extends Component {
state = { counter: 0 }

incrementCounter = () => {
this.setState(prevState => ({
counter: prevState.counter + 1,
}));
}
render() {
return (
<Button onClick={this.incrementCounter}>
...

This is actually a very quick fix as well if you think about it. It’s just not as noticeable when you look at it for the first time. This method performs better than the previous methods and has the added benefit of keeping your render function tidy too. However, it is still not the recommended approach according to the ReactJS documentation.

Bind in the Constructor: The “Recommended Fix”

The following method is recommended by the ReactJS documentation and has been thoroughly tested to be the solution that performs the best.

...
export default class CounterButton extends Component {
state = { counter: 0 }
constructor(props) {
super(props);
this.incrementCounter = this.incrementCounter.bind(this);
}
incrementCounter() {
this.setState(prevState => ({
counter: prevState.counter + 1,
}));
}
render() {
return (
<Button onClick={this.incrementCounter}>
...

This it the best practice way of doing things. It certainly isn’t the quickest fix, nor the cleanest. But given the way React works, it makes sense that this will be the method that performs best. The event handler is bound to this when the component is created. Which means it only occurs once, making it better than the first two “Quick Fix” solutions mentioned above. Since it is also React’s recommended solution, it performs slightly better than the third “Clean Fix” solution mentioned above. The core React developers always focus first on optimizing the best practice methods that they’ve documented.

Another great thing about this solution is that it keeps your render method clean just like the “Clean Fix” solution does.

What about transpilers which auto-bind your event handlers for you?

You do get transpilers out that there that can auto bind your event handlers for you which make all of these methods mentioned above completely redundant. However, these aren’t recommended for the two following main reasons.

Firstly, these transpilers aren’t maintained by the core React development team. Therefore if the core development team make any optimizations to React. Your transpiled code might not be following best practices set out by the core React team. It’s better to just stick to the documented standards than to take shortcuts like this.

Secondly, not every single event handler in your classes need to be bound to this! Only event handlers that use this actually need to be bound to this. For example, when this.state is used, or this.props or even this.someOtherEventHandler().

That hopefully answers the question: When shouldn’t you use .bind(this)? When this isn’t used in your event handler, your event handler doesn’t need to be bound to this. That’s a good excuse not to use auto-binding transpilers. However, usually when you have an event handler that doesn’t use this in it’s declaration. It means you can probably export it to a separate helper file or just declare it outside of your class declaration. That would make it a more reusable function and make your class less coupled.

Edit: I recently wrote a blog post on Sub Rendering over here. This a good example of where you don’t need to.bind(this) on everything in your React classes.

In Conclusion

The best way to .bind(this) in React is to do it in the component’s constructor method. This is recommended by the React core development team and is the method which provides the best performance.

Although it doesn’t really matter for smaller applications. It can’t hurt to opt for better performance when it doesn’t compromise on code readability and maintainability. Therefore, in this case go for the recommended solution!

This post was inspired by concepts written about in Code Complete: A Practical Handbook of Software Construction, Second Edition. Even though this book was written years before ReactJS was developed, the content is evergreen and extremely valuable!

Let me know in the comments below what your favorite way to bind(this) is!

Originally published at www.barrymichaeldoyle.com on August 28, 2018.

More where this came from

This story is published in Noteworthy, where thousands come every day to learn about the people & ideas shaping the products we love.

Follow our publication to see more product & design stories featured by the Journal team.

--

--