//

REACT & ES6

ES6 is here and now. So writing React JS components in ES6 will be beneficial considering the new features ES6 brings to us.

Let's look at some of these new features:

  • Classes
  • Enhanced Object Literals
  • Block-scoped binding constructs (let + const)
  • Property Initializers
  • Arrow Functions
  • Template Strings
  • Spread Attributes
  • Desconstructing Attributes
  • Generators
  • Data Structures (Map, Set, WeakMap, WeakSet)
  • ...and many more

Transpilers

We can use ES6 with transpilers to convert the source code into ES5, so that most of the browsers can still execute JavaScript source code.

Here are few popular transpilers:

  • Traceur
  • JSTransform (depreciated)
  • Babel

Babel

Babel was created by Sebastian McKenzie at the fall of 2014.

Babel supports JSX, ES6 and ES7. It is widely used including Facebook.

Classes

ES6 classes provide you with a concise way of writing React components:

Instead of using the React.createClass method to define a component, we can define a bonafide ES6 class that extends React.Component

ES5:

var Photo = React.createClass({
  handleDoubleTap: function(e) { … },
  render: function() { … },
});

ES6:

class Photo extends React.Component {
  handleDoubleTap(e) { … }
  render() { … }
}

Property Initializers

In ES6 property types and defaults are static properties of its class.

Component's initial state can be defined using ES6.

ES5:

var Video = React.createClass({
  getDefaultProps: function() {
    return {
      autoPlay: false,
      maxLoops: 10,
    };
  },
  getInitialState: function() {
    return {
      loopsRemaining: this.props.maxLoops,
    };
  },
  propTypes: {
    autoPlay: React.PropTypes.bool.isRequired,
    maxLoops: React.PropTypes.number.isRequired,
    posterFrameSrc: React.PropTypes.string.isRequired,
    videoSrc: React.PropTypes.string.isRequired,
  },
});

ES6:

class Video extends React.Component {
  static defaultProps = {
    autoPlay: false,
    maxLoops: 10,
  }
  static propTypes = {
    autoPlay: React.PropTypes.bool.isRequired,
    maxLoops: React.PropTypes.number.isRequired,
    posterFrameSrc: React.PropTypes.string.isRequired,
    videoSrc: React.PropTypes.string.isRequired,
  }
  state = {
    loopsRemaining: this.props.maxLoops,
  }
}

Arrow Functions

The React.createClass method used to perform some extra binding work on your component's instance methods to make sure that, inside them, the this keyword would refer to the instance of the component in question.

ES5:

// Autobinding, brought to you by React.createClass
var PostInfo = React.createClass({
  handleOptionsButtonClick: function(e) {
    // Here, 'this' refers to the component instance.
    this.setState({showOptionsModal: true});
  },
});

By combining two ES6 features – arrow functions and property initializers – opt-in binding to the component instance becomes a easier:

ES6:

class PostInfo extends React.Component {
  handleOptionsButtonClick = (e) => {
    this.setState({showOptionsModal: true});
  }
}

Dynamic property names & template strings

One of the enhancements to object literals include the ability to assign to a derived property name. We might have originally done something like this to set a piece of state:

ES5:

var Form = React.createClass({
  onChange: function(inputName, e) {
    var stateToSet = {};
    stateToSet[inputName + 'Value'] = e.target.value;
    this.setState(stateToSet);
  },
});

Now, we have the ability to construct objects whose property names are determined by a JavaScript expression at runtime. Here, we use a template string to determine which property to set on state:

ES6:

class Form extends React.Component {
  onChange(inputName, e) {
    this.setState({
      [`${inputName}Value`]: e.target.value,
    });
  }
}

Destructuring & spread attributes

Often when composing components, we might want to pass down most of a parent component's props to a child component, but not all of them. In combining ES6+ destructuring with JSX spread attributes, this becomes easier:

ES6:

class AutoloadingPostsGrid extends React.Component {
  render() {
    var {
      className,
      // contains all properties of this.props except for className
      ...others,
    } = this.props;
    return (
      <div className={className}>
        <PostsGrid {...others} />
        <button onClick={this.handleLoadMoreClick}>Load more</button>
      </div>
    );
  }
}

We can combine JSX spread attributes with regular attributes too, taking advantage of a simple precedence rule to implement overrides and defaults. This element will acquire the className “override” even if there exists a className property in this.props:

<div {...this.props} className="override">
  …
</div>

This element will regularly have the className “base” unless there exists a className property in this.props to override it:

<div className="base" {...this.props}>
  …
</div>