Andreas Reiterer
28 Feb 2018
•
5 min read
This might sound familiar to you: You run your React app after you made some changes to test your new functionality and get an error message like this: “this.setState
is not a function“. It’s probably because you forgot to bind a callback function before passing it down a prop. Today you’ll learn why you need to bind, and how to bind a callback function in React.
Handling the this
keyword is causing a lot of headaches for many developers. That’s because in JavaScript it is not always clear what this
is actually referring to. Especially, when you’re working with callback functions.
If you ask yourself, why you even have to bind callback functions and when you actually have to do this, this article is for you: Today we’re going to learn about binding the this
keyword in React components.
TL;DR: Binding callbacks is a JavaScript thing. It’s necessary because you have to tell your callback what it’s context is. Avoid binding by using the public class fields syntax, or bind your callbacks inside the constructor.
this
First of all, it’s not a React thing that you’ve got to bind this
. In fact, it’s related to the way JavaScript works. this
is a special keyword inside each function that refers to the current context. You might already have seen this
in other programming language.
In JavaScript however, the value of this
depends on how the function was called, not where or when it was defined. Also, it is not affected by scope, like a variable would be. This means, that whenever you pass a function down another function, this
will not refer to the same value.
function myFunction() {
console.log(this);
}
// Calling the function normally
myFunction(); // 'this' will refer to 'window'
// pass the function to an object and call it as an object method
var myObj = { doSomething: myFunction};
myObj.doSomething; // 'this' will refer to 'myObj'
If you want to learn more about this, I recommend having a look at the MDN documentation.
But what does all of that have to do with binding this, you ask? Well – it’s possible to tell a function what it’s this
should refer to – and that’s what you’re doing with binding this
. Let’s have a look at that.
this
If you bind a function, you can set the value of this for later, so it doesn’t matter anymore where exactly your callback function is called. You can achieve this by calling bind(this) for your function:
function myFunction() {
console.log(this);
}
// bind(this) creates a new function where the value of 'this' is fixed
var boundFunction = myFunction.bind(this);
// It's also possible to replace the function by it's bound version
myFunction = myFunction.bind(this);
Calling bind(this)
on a function returns a new (bound) function that has the value of this
already defined. This way, if you would pass it to another object, or down a prop inside a React component, the value of this inside this
component will not change anymore.
Now let’s have a look at how we can bind this
inside a React component.
The best way to show the different approaches is an example. Have a look at the components in the following code sample:
const AddComponent = ({onAdd}) => {
return (
<div>
<button onClick={() => {onAdd("item")}}>Add</button>
</div>
);
}
class MyListComponent extends Component {
constructor(props) {
super(props);
this.state = {
myObjects: []
}
}
handleAdd(newObject) {
this.setState((prevState) => (
Object.assign(
{},
this.state,
{ myObjects: [...prevState.myObjects, newObject] }
)
));
}
render() {
return (
<div>
<AddComponent onAdd={this.handleAdd} />
{this.state.myObjects}
</div>
)
}
}
What we have here is a simple Component that holds a list of items. A child component adds items to this list with the help of a callback passed through props. So far so good. If you execute the above example, you’ll get an error because this
is undefined.
In the following sections, I’m going to explain the recommended ways to bind this
to avoid such errors.
Even though this is the recommended way to bind your callbacks, it’s worth to note that public class fields syntax is not standardized yet. But they are already so widely used that if there would be syntax changes, it probably won’t take long for a proper frictionless migration strategy to appear.
When using the public class fields syntax, you’re going to transform your callback to a public field of your class. Doing so will bind the this
of the callback automatically to the class it was defined in. This allows you to pass the callback to your child component without having to bind it separately in your constructor.
handleAdd = (newObject) => {
this.setState((prevState) => (
Object.assign(
{},
this.state,
{ myObjects: [...prevState.myObjects, newObject] }
)
));
}
Another way to bind this
is to do so in your parent component’s constructor by calling .bind(this)
for your callback function:
constructor(props) {
super(props);
this.state = {
myObjects: []
}
this.handleAdd = this.handleAdd.bind(this);
}
That’s it! Basically, you just have to bind every callback function inside the constructor and you’re safe to go.
If you have a lot of callback functions you can probably imagine how big your constructor could get. If you compare this to using the public class fields syntax, you’ll notice that this approach means a bit more typing for you and a potentially bigger constructor.
In the previous sections, I explained the recommended ways of binding this
. However, if you don’t like the above-mentioned approaches, here are some more – if you are okay with their caveats.
Instead of binding the callback function in your constructor, you can do so while passing it through a prop:
<div>
<AddComponent onAdd={this.handleAdd.bind(this)} />
{this.state.myObjects}
</div>
Note: Whenever your component is re-rendered, bind(this)
returns a new function and passes it down your component tree. This may lead to unnecessary re-rendering of your child components. Down the road, this can have a massive impact on your app performance.
Instead of using the public class field syntax, you could directly pass an arrow function down your props:
<div>
<AddComponent onAdd={(obj) => this.handleAdd(obj)} />
{this.state.myObjects}
</div>
Note: Like in the previous example, this creates a new callback each time your component is re-rendered and may cause unnecessary re-rendering of your component tree. Again a performance impact that you might not want to put up with.
We won’t get around binding callback functions, since it’s how JavaScript works. But now that you know why we have to bind this
– and how to do it in React components, I hopefully made your life a bit easier.
As always there are different ways to solve this issue. But from the four mentioned approaches, I’d suggest sticking to one of the recommended options:
this
in the constructorDoing so might save you from unexpected performance issues. After you get used to using one approach, you won’t even think about it again.
Still not sure what’s the best approach for you? Take some time and try both of them! After you spent some time trying and practicing, you might notice that you like one approach more than the other – you’ll never know just by reading without trying it.
Now get your hands dirty and find your favorite approach!
If you’re passionate about Front End development, check out the JavaScript Works job-board here!
Ground Floor, Verse Building, 18 Brunswick Place, London, N1 6DZ
108 E 16th Street, New York, NY 10003
Join over 111,000 others and get access to exclusive content, job opportunities and more!