1
Write a post

Replacing this.functionName = this.functionName.bind(this) in Reactjs

Published Jul 08, 2017Last updated Jul 30, 2017

This post will explain how to replace those repetitive this.functionName = this.functionName.bind(this) with some good code that keeps complicated components clean.

After asking about how to fix this in a few comment sections on StackOverflow, I was not receiving useful help, only comments like "that's just part of React". I do not feel this boilerplate in every constructor is useful, but instead a flaw.

I eventually decided to try subclassing React's Component and iterate over a list of function names as strings to bind this, because that is what I would do in Python.

Luckily, now that ES6 has arrived, this is easy to do in Javascript too.

First, I Googled "es6 subclass". You should see the official Mozilla docs on classes come up in the top 5 hits like Classes - JavaScript | MDN. About halfway down, it says "Sub classing with extends" and gives an example.

In any React project you may have, make a file called something like MyComponent.js. We will need to import the standard React Component class as well. So far, we have:

MyComponent.js:

import React, { Component } from 'react';


class MyComponent extends Component {

}

Let's look at a typical React component:

SearchBar.js

import React, { Component } from 'react';

class SearchBar extends Component {
  constructor(props) {
    super(props);
    this.state = { term: '' };
    this.handleFormSubmit = this.handleFormSubmit.bind(this);
    this.onInputChange = this.onInputChange.bind(this);
    this.processInput = this.processInput.bind(this);
    this.sendSearchResults = this.sendSearchResults.bind(this);
  }

  render() {
    ...
  }
}

We can see that our goal with this subclass is to override the constructor, where the custom functions are registered and bound with this. We know that our goal is to simplify the code by passing in an array like

let custom_methods = [
  'handleFormSubmit', 
  'onInputChange', 
  'processInput', 
  'sendSearchResults'
];

Now we have:

MyComponent.js:

import React, { Component } from 'react';


class MyComponent extends Component {
  constructor(props, custom_methods) {
  
  }
}

Languages that have classes normally have a super builtin function, or something similar, that ensures the original code in the class we're extending is run. In other words, we want to override the Component class's constructor function, but we don't want to break our React app by losing all the builtin things Component provides for us. So, just like we do in a normal React Component, add super:

MyComponent.js:

import React, { Component } from 'react';


class MyComponent extends Component {
  constructor(props, custom_methods) {
    super(props);
  }
}

Now let's bind this to our custom methods, by iterating with map:

MyComponent.js:

import React, { Component } from 'react';


class MyComponent extends Component {
  constructor(props, custom_methods) {
    super(props);
    custom_methods.map((method_name) => {
      this[method_name] = this[method_name].bind(this)
    });
  }
}

We have a problem here though, that this code will break anytime a user doesn't have custom methods to pass in. If this constructor is called without the second argument, custom_methods will be undefined, and the error will occur when map tries to run. To see this, run the following code:

var unmappable = undefined;
unmappable.map(function(item) { console.log(item) })

You get:

Uncaught TypeError: Cannot read property 'map' of undefined
    at <anonymous>:2:11

To prevent this, we can use the new variable default syntax that should look similar to other languages. Default custom_methods to an empty array:

MyComponent.js:

import React, { Component } from 'react';


class MyComponent extends Component {
  constructor(props, custom_methods=[]) {
    super(props);
    custom_methods.map((method_name) => {
      this[method_name] = this[method_name].bind(this)
    });
  }
}

Now we have our finalized component. Let's refactor the search bar to see how to use it:

SearchBar.js

import MyComponent from './MyComponent';

class SearchBar extends MyComponent {
  constructor(props) {
    let custom_methods = [
      'handleFormSubmit', 
      'onInputChange', 
      'processInput', 
      'sendSearchResults'
    ];
    super(props, custom_methods);
    this.state = { term: '' };
  }

  render() {
    ...
  }
}

Notice the super call passes 2 arguments, whereas we usually only pass props to super in React components. This is because SearchBar extends MyComponent, and super calls the parent class's function of the same name. So here, since super is inside a method named constructor, the super(props, custom_methods) call is calling the constructor function of MyComponent, which takes 2 arguments, props, and the optional custom_methods.

Compare reading the above to the old-style:

import React, { Component } from 'react';

class SearchBar extends Component {
  constructor(props) {
    super(props);
    this.state = { term: '' };
    this.handleFormSubmit = this.handleFormSubmit.bind(this);
    this.onInputChange = this.onInputChange.bind(this);
    this.processInput = this.processInput.bind(this);
    this.sendSearchResults = this.sendSearchResults.bind(this);
  }

  render() {
    ...
  }
}

This makes my code slightly easier to maintain, but most importantly, this pattern makes my custom components much easier to read and understand at a glance. I hope you'll use this pattern in your React apps also.

Discover and read more posts from Cody Childers
get started
Enjoy this post?

Leave a like and comment for Cody

5
6
6Replies
Christoph Wagner
a month ago

Not to be the one to rain on your parade, but that’s not much of an improvement (you still have to explicitly name all the functions you want to bind), and it comes at a very heavy cost (having to subclass EVERY. SINGLE. COMPONENT).

The authors of React deliberately lean towards avoiding inheritance altogether in favor of composition. This is in order to avoid the so-called fragile base class problem.

This topic on StackOverflow discusses a number of different approached to the issue, however, unfortunately none of them are perfect. If you want to avoid this nasty business altogether, you might want to look into Vue.js instead.

Cody Childers
a month ago

Hey Christoph, I just read that article, but I’m also using this pattern a lot and it’s worked each time. I think facebook’s concerns about extending components are different, relating to you extending your own custom components (beyond just this constructor). Things like this are an annoyance and seem to be the responsibility of React to automate, I agree and have been learning a little Vue myself :)

Rico Alexander
a month ago

Nice article! Curious. I use typescript and use handleOnClick = () => {dosomething}; when setting function handlers. Is there a problem with doing it this way?

Cody Childers
a month ago

I’m not sure I normally use React, but this will help https://rainsoft.io/when-not-to-use-arrow-functions-in-javascript/. If you’re defining it on a class from what little I know of typescript I don’t see an issue

Matthew Brown
a month ago

Great article! I have just been getting into React and was wondering if there was a better solution to adding all those .bind’s in the constructor. Looks like your solution will do the trick. Thanks for sharing

Cody Childers
a month ago

Glad you liked it Matthew

Show more replies

Get curated posts in your inbox

Learn programming by reading more posts like this