about 8 years ago

A lot of react projects hosted on github use ES6/7 syntax. I had a lot of headaches when reading them since I am not familiar with the new syntax. I decided to learn it by converting a simple react project written in ES5 to ES6. I documented the transitions I made while conveting it to ES6/7.

Importing React

ES5

var React = require('react');
var ReactPropTypes = React.PropTypes;

ES6

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

To understand why there is no '{}' around React, let's take a look at react's source code:

var React = {
  ...
  Component: ReactComponent,   // both Component and PropTypes are like 'plain exports' in ES6

  PropTypes: ReactPropTypes,
  ...
}

module.exports = React;  /* this line is like the default export in ES6 */

In ES6, when importing a default export, there is no need to wrap it around {}, everything else has to be inside {}

Creating React Component and Exporting it

ES5

var Header = React.createClass({
    render: function() {
        return (
            <header>
                <h1>This is the header section</h1>
            </header>
        );
    }
});

module.exports = Header;

ES6

export default class Header extends Component {
    render() {
        return (
            <header>
                <h1>This is the header section</h1>
            </header>
        );
    }
}

You can use 'export default' if you don't care how the Header component will be named when it is imported, or use 'export' instead if you want to enforce its name.

PropTypes

ES5

var React = require('react');
var ReactPropTypes = React.PropTypes;

var Header = React.createClass({
    propTypes: {
      title: ReactPropTypes.string.isRequired
    }
});

ES6

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

export default class Header extends Component {
    render() {
        return (
            <header>
                <h1>This is the header section</h1>
            </header>
        );
    }
}

//Note that the propTypes has to be defined outside of the class definition

Header.propTypes = {
    title: PropTypes.string.isRequired
}

The ES6 syntax looks weird because the propTypes section is outside of the class definition. This is due to the fact that only methods can be defined inside a class in ES6. If you want to define properties, they have to be outside of the class.

To avoid this issue, I prefer to use ES7 Property Initialiazers:

ES7

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

export default class Header extends Component {

    // brings the propTypes inside the class definition

    // Note that propTypes belongs to the class, and thus it is static

    // non-static properties (instance properties) is shown in the next section

    static propTypes = {
        title: PropTypes.string.isRequired
    }

    render() {
        return (
            <header>
                <h1>This is the header section</h1>
            </header>
        );
    }
}

getInitialState

ES5

var Header = React.createClass({
    getInitialState: function() {
        return {
            title: this.props.title
        };
    },
});

ES6

export default class Header extends Component {
    constructor(props) {    /* Note props is passed into the constructor in order to be used */
        super(props);
        this.state = {
            title: props.title
        };
    }
}

To furthur simplify this code using ES7's property initializer:

ES7

export default class Header extends Component {
    // instance property

    state = {
        title: this.props.title
    };
    
    // followed by constructor...

}

Invoking Methods

Let's borrow an example from the offical react tutorial:

ES5

var Header = React.createClass({
    handleClick: function(event) {
        this.setState({liked: !this.state.liked});  // Note here that **this** is automatically bind to the componenet itself

    }
});

However in ES6, the React team decided to not automatically bind this to the component. So to rewrite the code above in ES6, we need to bind the handleClick function to the component inside the constructor:

ES6

export default class Header extends Component {
    constructor() { 
        super();
        this.handleClick = this.handleClick.bind(this);
    }
    
    handleClick(event) {
        this.setState({liked: !this.state.liked});  
    }
}

The React blog also suggested to use ES7 property initializers to make it even simpler:

ES7

export default class Header extends Component {
    handleClick = (event) => {
        this.setState({liked: !this.state.liked});  
    }
}

This code needs some explanation. The handleClick = ... part is ES7 property initializer stuff. The (event) => {} is ES6 fat arrow function which preserves this context when it is called.

There are quite a few ways to accomplish this using es6/7 but this is the simpliest way recommended by the React team.

Conclusion

These are the conversions needed to convert your code from ES5 to ES6/7. The new syntax reduces the amount of code and makes it look better IMO. It is definitely a good time to start learning the new syntax and using it in React.

← Python various ways to copy a list Ways to Pump Data to your React App (and Django) →
 
comments powered by Disqus