ES6 is here and now. So writing React JS components in ES6 will be beneficial considering the new features ES6 brings to us.
Давайте посмотрим на некоторые из этих новых возможностей:
- Классы
- Расширения объектых литералов
- Block-scoped binding constructs (let + const)
- Property Initializers
- Стрелочные функции
- Template Strings
- Desconstructing и Spread аттрибуты
- Генераторы
- Data Structures (Map, Set, WeakMap, WeakSet)
- ... и многое другое
Транспайлеры
Мы будем мспользовать ES6 с транспайлерами для конвертирования нашего кода в ES5-стандарт, поскольку код, написанный на ES6, современным браузерам "не по зубам". Вот несколько популярных транспайлеров: Traceur, Babel.
Babel
Babel был создан Себастьяном МакКензи at the fall of 2014. Babel поддерживает JSX, ES6 и ES7. It is widely used including Facebook.
Классы
ES6 classes provide you with a consize way of writing React components:
Instead of using the React.createClass method to define a component, we can define a bonafide ES6 class that extends React.Component
//ES5
var Photo = React.createClass({
handleDoubleTap: function(e) { … },
render: function() { … },
});
//ES6
class Photo extends React.Component {
handleDoubleTap(e) { … }
render() { … }
}
Property Initializers
In ES6 property types and defaults are static properties of its class.
Начальное состояние компонента может быть определено с помощью ES6.
//ES5
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
},
});
//ES6
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,
}
}
Стрелочные функции
Метод React.createClass
used to perform some extra binding work on your component’s instance methods to make sure that, inside them, the this keyword would refer to the instance of the component in question.
//ES5
// Autobinding, brought to you by React.createClass
var PostInfo = React.createClass({
handleOptionsButtonClick: function(e) {
// Здесь 'this' относится к экземпляру компонента
this.setState({showOptionsModal: true});
},
});
Объединив две фичи ES6 - стрелочные функции и property initializers – opt-in binding to the component instance becomes a easier:
//ES6:
class PostInfo extends React.Component {
handleOptionsButtonClick = (e) => {
this.setState({showOptionsModal: true});
}
}
Dynamic property names & template strings
One of the enhancements to object literals includes the ability to assign to a derived property name. We might have originally done something like this to set a piece of state:
//ES5
var Form = React.createClass({
onChange: function(inputName, e) {
var stateToSet = {};
stateToSet[inputName + 'Value'] = e.target.value;
this.setState(stateToSet);
},
});
Now, we have the ability to construct objects whose property names are determined by a JavaScript expression at runtime. Here, we use a template string to determine which property to set on state:
//ES6
class Form extends React.Component {
onChange(inputName, e) {
this.setState({
[`${inputName}Value`]: e.target.value
});
}
}
Destructuring & spread attributes
Often when composing components, we might want to pass down most of a parent component’s props to a child component, but not all of them. In combining ES6+ destructuring with JSX spread attributes, this becomes easier:
//ES6
class AutoloadingPostsGrid extends React.Component {
render() {
var {
className,
// содержит все свойства this.props за исключением Classname
...others,
} = this.props;
return (
<div className={className}>
<PostsGrid {...others} />
<button onClick={this.handleLoadMoreClick}>Загрузить еще</button>
</div>
);
}
}
We can combine JSX spread attributes with regular attributes too, taking advantage of a simple precedence rule to implement overrides and defaults. This element will acquire the className “override” even if there exists a className property in this.props:
<div {...this.props} className="override">
...
</div>
This element will regularly have the className “base” unless there exists a className property in this.props to override it:
<div className="base" {...this.props}>
...
</div>