Properly using .bind() in React and understanding the prototype chain

Dimitris Karagiannis
webmonkeys
Published in
7 min readJan 15, 2018

Prologue

If you’ve been using React since before version 15, you will surely remember the old way of declaring component classes, where you would write something like this:

var MyComponent = React.createClass({
methodOne: function(someValue) {
/* ... */
this.setState({ someState: someValue})
},
methodTwo: function(someOtherValue) {
/* ... */
this.setState({ someOtherState: someOtherValue})
},
render: function() {
return (
/* ... */
<button onClick={this.methodOne}>
Click me!
</button>
) ;
}
});

Now, those were the times, right? All you had to do was define your component’s methods and then you could simply use them and pass them around, wherever they were needed, without having to think twice.

But then React 15.5 came and along with it came deprecations. Suddenly React.createClass() was no longer a first class citizen and moving forward you had to start using ES6’s new class feature. So, you would now write your code above like this:

class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state={/*...*/};
}

methodOne(someValue) {
/* ... */
this.setState({ someState: someValue})
}
methodTwo(someOtherValue) {
/* ... */
this.setState({ someOtherState: someOtherValue})
}
render() {
return (
/* ... */
<button onClick={this.methodOne}>
Click me!
</button>
) ;
}
}

Everything looks good and your application builds correctly. Well, that was easy. But then you click on that button, that ever so persistently calls you to click on it, and nothing happens. You open the console and you see something among the lines of Uncaught TypeError: this.setState is not a function .

So you realize (maybe after googling the error for a bit) that when you click on the button and methodOne is called, the this context is wrong.

“Well of course!” you tell to yourself. The new React does not automatically bind this to the correct context as the older version used to do.

“I’ll just have to .bind() all of my component’s methods to this , inside the constructor, and everything will be working fine again”

And so you do. And you reach a point where the majority of your constructor functions look like this:

constructor(props) {
super(this);
this.state = {/*...*/};
this.methodOne = this.methodOne.bind(this);
this.methodTwo = this.methodTwo.bind(this);
this.methodThree = this.methodThree.bind(this);
/*.....*/
this.methodGorillionMinusOne = this.methodGorillionMinusOne.bind(this);
this.methodGorillion = this.methodGorillion.bind(this);
}

But everything works, so all is well. Or is it?

The magic of prototypical inheritance and the prototype chain

If you would like to skip on some technical explanations feel free to skip this section and jump straight to “Tying it all back to React below.

Let’s examine a simple JavaScript class written in ES6:

class SomeClass {
constructor(config) {
this.instancePropertyOne = config.one;
this.instancePropertyTwo = config.two;
this.instancePropertyThree = config.one + config.two;
}
classMethodOne = function classMethodOne() {
console.log(this.instancePropertyOne);
}
classMethodTwo = function classMethodTwo() {
console.log(this.instancePropertyTwo);
}
}

And now let’s step back a little and let’s see how we would write it in the ES5 way:

function SomeClass(config) {
this.instancePropertyOne = config.one;
this.instancePropertyTwo = config.two;
this.instancePropertyThree = config.one + config.two;
}
SomeClass.prototype.classMethodOne = function classMethodOne() {
console.log(this.instancePropertyOne);
}
SomeClass.prototype.classMethodTwo = function classMethodTwo() {
console.log(this.instancePropertyTwo);
}

And to test it:

const config = {one: 1, two: 2}
const someClassInstance = new SomeClass(config);
someClassInstance.classMethodOne(); // prints 1
someClassInstance.classMethodOne(); // prints 2
someClassInstance.instancePropertyThree; //prints 3

Now let’s take a closer look.

When we define the class, internally the JavaScript engine does something like this:

function SomeClass(config) {
this.instancePropertyOne = config.one;
this.instancePropertyTwo = config.two;
this.instancePropertyThree = config.one + config.two;
}
// The following is an approximation of what happens internally:
// SomeClass.prototype = {constructor: SomeClass};
SomeClass.prototype.classMethodOne = function classMethodOne() {
console.log(this.instancePropertyOne);
}
SomeClass.prototype.classMethodTwo = function classMethodTwo() {
console.log(this.instancePropertyTwo);
}

And when we create a new instance of SomeClass with new SomeClass() something like the following happens:

function SomeClass(config) {
// The following is an approximation of what happens internally:
//this = {
__proto__: SomeClass.prototype
};

this.instancePropertyOne = config.one;
this.instancePropertyTwo = config.two;
this.instancePropertyThree = config.one + config.two;
}

As you can see each instance of SomeClass points to the prototype object (or __proto__ ) that is attached to the SomeClass constructor function. The word “points” is of importance here, since almost every variable, property or method in JavaScript is just a pointer to an object instance or primitive value.

This is the prototype chain.

Every object instance, created within the JavaScript environment, points to another prototype object instance called __proto__ , that was provided to it from its constructor function, thus creating a chain.

Start reading from left to right, starting with “var foo = new Foo()”. Source

So, we explained the prototype chain, but what is the prototypical inheritance?

You may have noticed that in our previous class usage example, the SomeClass instance does not actually have any methods on itself. It only has three properties: instancePropertyOne , instancePropertyTwo and instancePropertyThree .

However, when we create a new SomeClass instance and we call someClassInstance.classMethodOne() it works. Why is that so?

That’s because whenever you evaluate a property or a method on an object instance, the JavaScript engine, starting with the object instance itself, will traverse all the __proto__ objects in the the instance’s prototype chain, trying to find a matching property/method key in any of them. If it finds one it will stop searching further and it will use its value.

This is the prototypical inheritance.

As long as any __proto__ object in the prototype chain of an object instance has a property or method with the key/name we are looking for, then it acts as if the object instance itself had the property/method on itself.

If we were trying to use a method that exists in one of the object’s instance __proto__ and we called it as SomeClassInstance.somePrototypeMethod the context for this will be the object instance upon which the method was called (in this case SomeClassInstance ).

So what does this all mean?

The beauty of the prototypical inheritance and the prototype chain, is that even if you have an infinite number of a class’ instances and they all inherit a method from their prototype (class) then all of them will just point to a singular memory address where the prototype method lives.

In essence you are saving memory by allowing all your class instances to use the same function instance by reference.

Foo is a constructor function. b and c are instances of Foo. b and c both share a common prototype and all its methods and properties.

Each time .bind() is called, on the other hand, it creates a new discrete function instance which has to be stored separately in memory.

function SomeClass(config) {
this.instancePropertyOne = config.one;
this.instancePropertyTwo = config.two;
this.instancePropertyThree = config.one + config.two;

// Each instance creates two new functions and references them
this.classMethodOne = this.classMethodOne.bind(this);
this.classMethodTwo = this.classMethodTwo.bind(this);
}SomeClass.prototype.classMethodOne = function classMethodOne() {
console.log(this.instancePropertyOne);
}
SomeClass.prototype.classMethodTwo = function classMethodTwo() {
console.log(this.instancePropertyTwo);
}

In the code above, if we created 3 SomeClassInstance, 6 new functions would be stored in the memory, when we could use just the 2 initial functions for every SomeClassInstance. Do that thousands of times, instead of 3, and the memory will start filling up gradually.

Tying it all back to React

Applying all the above to React we now realise that .bind ing each and every component method to each component's instance is not a very efficient way to do things if we want to minimize our memory footprint.

(tl;dr if you skipped the two sections above: Every time you call .bind() on a component method you store an extra function in memory, while you could be using the reference to the original method and take advantage of the prototypical inheritance)

That’s especially true when working with big React applications where it’s a common occurrence to have multiple instances of some components.

So what do we do? A good rule of thumb is this:

Does your component have a class method that you need to pass down as a handler to a child component? Then this method needs to be bound to the correct component instance.

That’s because when you pass a method down to a child component as a handler function, you are essentially executing that function from the context of a different object instance, where this is not the one that the method expects.

Example:

class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state={/*...*/};

this.methodOne = this.methodOne.bind(this);
}

methodOne(someValue) {
/* ... */
this.setState({ someState: someValue})
}
render() {
return (
/* ... */
<button onClick={this.methodOne}>
Click me!
</button>
) ;
}
}

Every other class method that is only used internally from the component instance does not need to be bound to the component instance.

Example:

class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state={/*...*/};
this.methodOne = this.methodOne.bind(this);
}

methodOne(someValue) {
/* ... */
this.methodTwo();
this.setState({ someState: someValue})
}
methodTwo(someOtherValue) {
/* ... */
this.methodThree()
}
methodThree() {
// Do something with "this"
}
render() {
return (
/* ... */
<button onClick={this.methodOne}>
Click me!
</button>
) ;
}
}

As you can see only methodOne needs to be bound to the component instance since it has to be passed down to a child component as an onClick handler. methodTwo and methodThree do not need to be bound. This way, every MyComponent instance you create will only add one extra function to the memory and for the rest it can use the same MyComponent.prototype methods.

So, next time you try to optimise your React components, keep in mind that unnecessary usage of .bind() can matter.

Thanks for reading! 🖖

Further reading

--

--

Dimitris Karagiannis
webmonkeys

Frontend engineer, working with the Javascripts and the HTMLs and the CSSs. Hardware tinkerer and music enthusiast. Co-founder of Sourcelair.