Write a post

Enjoy this post? Give Cody Childers a like if it's helpful.

5
6

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

Published Jul 08, 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

Subscribe to our weekly newsletter