Autobinding, React and ES6 Classes

Moving from React 0.12 to 0.13 has seen us at Ticket Arena embrace many of the new features ES6 brings to JavaScript. We've been using Babel and Webpack to ensure we maintain browser compatibility while getting access to as many of the new features as possible.

In particular, we've been writing out React Components using classes and they look something like this:

import React from 'react';
let {Component, PropTypes} = React;

export default class MyComponent extends Component {
  // lifecycle methods and statics
  
  ...

  // render actual DOM output
  render() {
    return <div></div>;
  }
}

MyComponent.propTypes =  {
  foo: PropTypes.bool.isRequired
}

Several of the features we've come to rely on in previous versions of React have been removed, notably the Mixin but also, less obviously, Autobinding.

Autobinding with React.createClass

Previously, you could use this.handler in an eventListener and React would magically bind the handler to the current object's lexical this -this.handler === this.handler.bind(this). However, the move to ES6 Classes saw the removal of this feature but thankfully there is a super simple workaround, fat arrow functions!

You can see the details of the Facebook implementation in the source code for ReactClass

Fat Arrow Functions

Fat arrow functions don't define their own this value, instead they are bound to the lexical this of their current context. So (x) => this.y * x is effectively the same as function(x) { return this.y * x}.bind(this)

How can we use this with React? Well, there is a slight problem, ES6 doesn't allow for property initialisers (so no foo = 'bar'; inside class definitions). However, it is supported by Babel, you just need to set the following config "optional": ["es7.classProperties"].

Putting this all together using our previous code, we can mimic auto-binding:

import React from 'react';
let {Component, PropTypes} = React;

export default class MyComponent extends Component {
  // lifecycle methods and statics
  static propTypes = {
    foo: PropTypes.bool.isRequired
  }

  handler = (e) => { ... }

  // render actual DOM output
  render() {
    return <div onClick={this.handler}></div>;
  }
}

You can see more information about this technique on the official React blog