What React component class syntax should I use?
There are three different ways to define your React components. With v0.13 version of React, the dev team took a great effort to enable using pure JavaScript classes available in the new ECMAScript 2015 standard. Using such classes allow you to write more idiomatic JavaScript. It also introduces less magic than the old React.createClass
syntax. Each of these approaches have the slight differences and consequences when using them.
In this blogpost I want to show you examples of component classes written using React.createClass
, pure ECMAScript 2015 classes and ECMAScript 2015 classes with the experimental class properties feature. This will allow you to choose wisely between those three depending on your project needs.
React.createClass
The oldest syntax that React provides is the React.createClass
syntax. Of course you can express everything that you may express using other approaches with it. It allows you to use mixins which can be good for organizing your code. What is more, all methods defined with this syntax are auto-binded to the component instance - that means this
always points to the component itself. While it may be a less ‘pure’ approach than with the rest of approaches, it is generally very convenient. It is rare case when you do not want to bind your component methods to the component. Such unbound method does not have an access to properties and state. With React.createClass
syntax this problem is non-existent.
With this syntax you define initial state and props in a little different way. You must define special methods called getInitialState
and getDefaultProps
. In ES6 classes default props are passed using defaultProps
class property and initial state is set within a constructor. The constructor’s equivalent in this syntax is the componentWillMount
lifecycle method.
Since React dev team aim to solve problems by using language idioms and features, this is likely that this syntax would get deprecated in future. Right now it is still a great way to define your component classes. It is also the only choice when you can’t use ES6 transpiler like Babel in your project - with this syntax you use only ES5 features of JavaScript. That means you can omit the build system completely when building components with this syntax.
This is an example of the component written with React.createClass
syntax:
ECMAScript 2015 (ES6) classes
With React 0.13 there comes a possibility to write your React component classes with the ECMAScript 2015 class syntax. It makes your component class more ‘JavaScripty’, allowing you to write an idiomatic JS. This unfortunately has its issues - since they are pure JS classes, you have to bind your functions by yourself. Also with this approach there is no way to use React mixins. What you gain is that React component class syntax will follow the syntax of your whole code. Also, you can’t be surprised by React.createClass
behaviour like autobinding or different named methods. It is also a bit less verbose syntax than the React.createClass
one.
This is a Greeter
component example from above, rewritten using ECMAScript 2015 class syntax:
As you may see, in constructor method you can set the state - removing the getInitialState
function completely. Default properties are made by defining a class property defaultProps
. This can be a little weird for you that those default properties are defined outside the class. Unfortunately, without experimental extensions they can’t be defined in an another way. What’s worth to notice is that handleChange
method is bound to the component’s instance by hand in a constructor. This can be a bit verbose when you create many methods within the component class.
ECMAScript 2015 (ES6) classes with class properties
There is a proposal to extend ECMAScript 2015 class syntax to enable defining properties outside the methods of the class. This proposal also allows you to use arrows which are bound to the scope they’re defined by default. What is more, with this extension you’d be able to define class properties within the class using the static
keyword.
This seems to be a perfect fix for problems with ECMAScript 2015 syntax described above. The good information is that this proposal is already implemented in a Babel transpiler - that means you can use it today! All you need to do is enabling stage 0 features in the Babel itself. This can be done by using the stage
Babel option.
What you need to be aware, though - it is a Stage 0 proposal. That means its support can be rejected - and removed entirely from Babel in the next versions. You need to be careful when it comes to updating Babel. But it is fairly easy to rewrite component classes to not use the new, experimental syntax. The choice is up to you.
This is an example of a component class written this way (unfortunately I can’t show it in a jsbin since it does not support this Babel extension):
class Greeter extends React.Component {
state = { name: this.props.initialName };
static defaultProps = { initialName: "World" };
handleChange = ev => {
let { value } = ev.target;
this.setState({ name: value });
};
render() {
return(
<div className="greeter">
<p key="greeter">Hello, {this.state.name}!</p>
<label key="changeGreeterLabel">
Change greeting:
<input type="text" value={this.state.name}
name="greeted" onChange={this.handleChange}
/>
</label>
</div>
);
}
}
React.render(<Greeter />, document.body);
You can read more about this syntax in this Babel blogpost.
Summary
There is a freedom of how you can define React component classes. Each of these choices has its consequences. React dev team strongly suggests to shift from React.createClass
syntax to ECMAScript 2015 classes. They also encourage to use experimental class properties syntax to make your life easier with binding methods. The choice is up to you - but remember to cover yourself with tests when designing your component classes with experimental features.