In this year's new design of Instagram Web, I like to use some new ES6 + features when writing React components. Allow me to list these new features that can change the way you write React applications. These features can make you at least easier and more interesting than ever before! _____________
Class
The most obvious change in using ES6 + to write React components is the way we define the syntax of components (classes). Instead of using React.createClass to create classes, we can define an ES6 class that inherits React.Component:
class Photo extends React.Component {
render() {
return <img alt={this.props.caption} src={this.props.src} />;
}
}
We can find that this writing makes the way of defining components more concise:
// The ES5 way
var Photo = React.createClass({
handleDoubleTap: function(e) { … },
render: function() { … },
});
// The ES6+ way
class Photo extends React.Component {
handleDoubleTap(e) { … }
render() { … }
}
In this way, we can write a pair of parentheses, a semicolon, colons and function keywords for each method less.
All life cycle approaches can be defined in this way. However, the component WillMount can also be replaced by a constructor:
// The ES5 way
var EmbedModal = React.createClass({
componentWillMount: function() { … },
});
// The ES6+ way
class EmbedModal extends React.Component {
constructor(props) {
super(props);
// Operations usually carried out in componentWillMount go here
}
}
property initializers
In the ES6 + class, the attribute type prop type and default attribute default prop can be declared by static in the class. At the same time, the initial state of the component state) can be accessed through ES7's ___________ property initialization initializers) To complete:
// The ES5 way
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,
},
});
// The ES6+ way
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,
}
}
In ES7, the attribute initialization operation under the constructor points to an instance of the class, so the initial state state can be set by this.prop (that is, the parameters passed in).
Arrow function
The React.createClass method does some additional binding work on your component to ensure that within the method of the component real instance, this points to the component instance itself.
// 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});
},
});
Since we did not use React.createClass to define classes in ES6 + grammar, it seems that we have to manually bind the directions of this in these methods:
// Manually bind, wherever you need to
class PostInfo extends React.Component {
constructor(props) {
super(props);
// Manually bind this method to the component instance...
this.handleOptionsButtonClick = this.handleOptionsButtonClick.bind(this);
}
handleOptionsButtonClick(e) {
// ...to ensure that 'this' refers to the component instance here.
this.setState({showOptionsModal: true});
}
}
Fortunately, the ES6 + Arrow functions and property initializers make it very simple to point this function to an instance bound to a component:
class PostInfo extends React.Component {
handleOptionsButtonClick = (e) => {
this.setState({showOptionsModal: true});
}
}
This object in the body of a function binds the object defined, not the object used. property initializers happen to be in this scope.
Dynamic Property Name-String Template
Extensions to object literals in ES6 + allow us to use expressions to name attributes in object literals. If it's in ES5, we may have to do this:
var Form = React.createClass({
onChange: function(inputName, e) {
var stateToSet = {};
stateToSet[inputName + 'Value'] = e.target.value;
this.setState(stateToSet);
},
});
However, in ES6 +, we can use expressions not only in the definition of object literal attributes, but also in the use of string templates:
class Form extends React.Component {
onChange(inputName, e) {
this.setState({
[`${inputName}Value`]: e.target.value,
});
}
}
Destruction-Extension Operator
In the process of composing components, we often encounter the situation that many of our attributes are passed from the parent component to the child component. With ES6 + destructive and extended operator features, this becomes very convenient:
class AutoloadingPostsGrid extends React.Component {
render() {
var {
className,
...others, // contains all properties of this.props except for className
} = this.props;
return (
<div className={className}>
<PostsGrid {...others} />
<button onClick={this.handleLoadMoreClick}>Load more</button>
</div>
);
}
}
We can combine extension operator attributes with common attributes, so that we can use priority to use default values of attributes and overrides of attributes. The following element obtains an override class, passing the className attribute in this.props in time.
<div {...this.props} className="override">
…
</div>
In the following way, you can set the default className for the element:
<div className="base" {...this.props}>
…
</div>
Last
I hope you can enjoy the benefits of these ES6 + features in writing React.js. Thank my colleagues for their contributions to this article and, in particular, the Babel team for allowing us to use these features at will.
Article Address: http://blog.mcbird.cn/2015/09/11/react-on-es6-plus/