Porting a Rails frontend from CoffeeScript to ES6 and JSX - examples
… and check why 5600+ Rails engineers read also this
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.