React and ES6 Today

Are you excited about ECMAScript 6? We are. ES6 is the new JavaScript with great new features that make JS easier to write and maintain. ES6’s classes, arrow functions and modules make JavaScript sane enough that we’re considering dropping CoffeeScript and swearing off all languages that compile to JavaScript.

ES6 in Today’s Browsers

Here’s the bad news. Today’s browsers have crummy ES6 support. For most projects, you can’t release ES6 code and expect end users to be able to run it.

Good news: there are tools like Babel (formerly 6to5) that will translate ES6 into the old syntax for you. This means you can write code using many (but not all) ES6 features, translate it, and run it in today’s browsers.

React and ES6

React and ES6

The React 0.13.x series adds support for ES6 classes! Babel even includes JSX support by default in recent versions!

So this means we live in a glorious React and ES6 future, right? Well, sort of. I recently spent some time with Babel and React and I found some things to consider before jumping in.

Firstly, 0.13x, as of the time of writing, is only a release candidate. RCs are to gauge your upgrade path to a new version and allow for bug fixes before an official release. The team promises you nothing until the version number has no letters after it. That’s just how this stuff works.

It is also important to note that React works differently when you are using ES6 classes. Some parts translate directly:

class HelloMessage extends React.Component {
  render() {
    return <div>Hello {this.props.name}</div>;
  }
}

React.render(<HelloMessage name="Sebastian" />, mountNode);

Some properties of React components are actually class/static properties and React will treat them as such when you are using ES6 classes. This means you will need to define some things (e.g. defaultProps and propTypes) as constructor properties, like this:

export class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {count: props.initialCount};
  }
  tick() {
    this.setState({count: this.state.count + 1});
  }
  render() {
    return (
      <div onClick={this.tick.bind(this)}>
        Clicks: {this.state.count}
      </div>
    );
  }
}
Counter.propTypes = { initialCount: React.PropTypes.number };
Counter.defaultProps = { initialCount: 0 };

To me, this reads as less declarative than the React.createClass form with which I’m familiar. It makes sense because ES6 lacks a syntactic shortcut for defining class or static properties in a the class definition, but I still prefer the way the React.createClass looks.

React’s magic autobinding of this doesn’t happen with ES6 classes. The rationale is that if React components are going to be ES6 classes, then they should have the same binding and scoping rules as any other ES6 classes so that developers don’t get confused when switching between React and non-React classes. I understand this, but I expect this change to confuse developers who have learned the old behavior.

Mixins are not supported if you opt for ES6 classes. ES6 doesn’t have a preferred mixin mechanism, so the React team opted to not include any system for mixins at all. I personally disagree with this decision, because React already has a mixin system that works just fine. I wish they would ship with the current system in place for all React components. When/if ECMAScript gets an official mixin mechanism they could make the switch to that.

Outside of React itself, I also had an issue that is likely to impact development of JS applications with ES6: some popular JavaScript libraries do not mesh well with the ES6 transpilers. Babel defaults to strict mode, but it seemed that Backbone and Underscore (for example) were not valid in strict mode. I guess this shouldn’t surprise me. I ended up turning off strict mode in Babel for this reason, but I hope to be able to re-enable it once more libraries are compatible.

In summary, I’d say that the day you can write applications with ES6 is closer than I initially thought, but there are still some hurdles to cross. I’d consider ES6 for a new application where you have more flexibility to choose your libraries and where you don’t have to rewrite existing code for React’s different behavior with ES6 classes. For a large existing application, the switch to ES6 needs to be made more deliberately for now.

More Posts by Robert Prehn: