ES6 classes as React components

Friday, Jan 30 2015 in react

The upcoming JavaScript standard, commonly referred to as ES6, will introduce a new syntax to define classes. With React 0.13, you can do without React.createClass and define components with plain functions. You can use ES6 classes to smooth the component definition process. Let’s see how it works.

The React functionality is available in the 0.13 beta. Of course, ES6 classes are not implemented in any browser yet, so you will need a transpiler. Luckily, react-tools, the same tool that you use to compile JSX, can also handle ES6 classes. The only thing you need to change in your build to use the --harmony flag if you didn’t already.

The first thing you’ll notice is that JavaScript class definitions have a different syntax than objects: you do not use a colon and the function keyword to declare member functions; instead, you just write the function name followed by the its body:

class Button {
    render() {
        return <button>{this.props.number}</button>
    }
}

You can also use the extends keyword to inherit from a base class. This is classic JavaScript prototypical inheritance, so in a sense, ‘class’ is a misnomer.

class Button extends React.Component {
    render() {
        return <button>{this.props.number}</button>
    }
}

It is strictly equivalent to

var Button = function() {React.Component.apply(this, arguments)}; // run parent 'constructor'
Button.prototype = Object.create(React.Component.prototype); // copy parent prototype
Button.prototype.render = function() { // define methods
  return <button>{this.props.number}</button>
}
Button.prototype.constructor = Button; // make 'constructor' point to the right function

ES6 classes just add more a concise way to achieve something that could be already done. In this case, we do not even need to inherit from React.Component, since Button is probably stateless. The more significant change lies in React itself.

React has been refactored to be able to use any function that can construct an object as the basis for a component. A stateful component, though, needs to call setState when its internal state changes. React 0.13 also introduces React.Component, that you can use to ‘inherit’ the setState function as needed.

class Calculator extends React.Component {
  constructor() {
    this.state = {result: 0};
  }
}

Name a member function constructor and it will run when the object is created: putting code inside constructor is the same as putting it into the body of the Calculator function if you defined ‘classes’ with the classic method. The end result will be equivalent to this code:

var Calculator = function() {
    React.Component.apply(this, arguments);
    this.state = {result: 0};
};
Calculator.prototype = Object.create(React.Component.prototype);
Calculator.prototype.render = function() {
  return <input type="text" value={this.state.result}/>;
}
Calculator.prototype.constructor = Calculator;

var myCalculator = new Calculator(); // this points to myCalculator

Now Calculator has a setState() method because setState is defined on React.Component’s prototype. In a React 0.13 app, we can use constructors to replace getInitialState(), as we are doing in this Calculator class to set the initial display to 0.

React 0.13 will allow more generic mechanisms to define components. ES6 classes are (mostly!) syntactic sugar.