Porting a Rails frontend from CoffeeScript to ES6 and JSX - examples

We are working on a new version of our bestseller book - Rails meets React.js. Currently, the book is based in CoffeeScript and we want to port it to ES6. The update will be free for everyone, who bought the CoffeeScript version

Here are some examples showing a process of porting from CoffeeScript to ES6 and JSX.

JSX

In our previous version of this book, we didn’t use JSX because it does not fit well with CoffeScript. With ES6 it is different, JSX fits here very well.

Before:

Stats = React . createClass contextTypes : user : React . PropTypes . object render : -> React . DOM . div null , "Won: #{ @ context . user . won } " React . DOM . br null "Lost: #{ @ context . user . lost } " React . DOM . br null React . DOM . a href : "http://www.example.org/stats/ #{ @ context . user . id } " , "(see the whole stats of #{ @ context . user . name } )" stats = React . createFactory ( Stats )

After:

class Stats extends React . Component { render () { return ( < div > Won { this . context . user . won } < br /> Lost { this . context . user . lost } < br /> < a href= { `http://www.example.org/stats/${this.context.user.id}` } > (see the whole stats of { this . context . user . name } ) </ a > </ div > ); } }

Note ES6 template literal ` http://www.example.org/stats/${this.context.user.id} ` which we are using to construct string url.

ES6 classes

Instead of using React.createClass we are now using ES6 class syntax:

Before:

OneTimeClickLink = React . createClass render : -> React . DOM . div ( { id : "one-time-click-link" }, React . DOM . a ( { href : "javascript:void(0)" }, "Click me" ) )

After:

class OneTimeClickLink extends React . Component { render () { return ( < div id = "one-time-click-link" > < a href = "javascript:void(0)" > Click me </ a > </ div > ); }

State initialization

Since getInitialState does not work with classes syntax, we are initializing state in a constructor. Like in this example:

Before:

DateWithLabel = React . createClass getInitialState : -> date : new Date () render : -> DOM . div

After:

class DateWithLabel extends React . Component { constructor ( props ) { super ( props ); this . state = { date : new Date () }; } render () { return (< div ></ div >); } }

Bind instance methods

In class syntax, React doesn’t bind all methods automatically. So, we are binding them in our constructor.

Before:

OnOffCheckbox = React . createClass getInitialState : -> toggled : false toggle : -> @ setState toggled : ! @ state . toggled render : -> React . DOM . input key : 'checkbox' type : 'checkbox' id : @ props . id checked : @ state . toggled onChange : @ toggle

After:

class OnOffCheckbox extends React . Component { constructor ( props ) { super ( props ); this . state = { toggled : false }; this . toggle = this . toggle . bind ( this ); } toggle () { this . setState ({ toggled : ! this . state . toggled }); } render () { return ( < input key= "checkbox" type= "checkbox" id= { this . props . id } checked= { this . state . toggled } onChange= { this . toggle } /> ); } }

Default props and validations

defaultProps , propTypes and contextTypes must be defined outside the class body. Here are some examples:

Before:

OnOffCheckbox = React . createClass getDefaultProps : -> initiallyToggled : false getInitialState : -> toggled : @ props . initiallyToggled toggle : -> @ setState toggled : ! @ state . toggled render : -> React . DOM . input key : 'checkbox' type : 'checkbox' id : @ props . id checked : @ state . toggled onChange : @ toggle

After:

class OnOffCheckbox extends React . Component { constructor ( props ) { super ( props ); this . state = { toggled : props . initiallyToggled }; this . toggle = this . toggle . bind ( this ); } toggle () { this . setState ({ toggled : ! this . state . toggled }); } render () { return ( < input key= "checkbox" type= "checkbox" id= { this . props . id } checked= { this . state . toggled } onChange= { this . toggle } /> ); } } OnOffCheckboxWithLabel . defaultProps = { initiallyToggled : false };

The same goes for propTypes :

Before:

Blogpost = React . createClass propTypes : name : React . PropTypes . string . isRequired # ...

After:

class Blogpost extends React . Component { // ... } Blogpost . propTypes = { name : React . PropTypes . string . isRequired };

Summary

Code written in ES6 with JSX can be pretty clean. I’ve used ESLint which helped me to keep syntax clean and free of errors. Here you can find a Blogpost how correctly configure it for your editor.

If you are interested in learning how to use React with Rails, with the ES6 syntax, we are working on a new version of Rails meets React.js. It will be free for everyone who bought previous CoffeeScript version.