Это перевод поста Steven Luscher опубликованного в блоге Babel. Steven работает в Facebook над Relay – JavaScript фрэймворком для создания приложений с использованием React и GraphQL.
За этот год, в процессе реорганизации Instagram Web, мы насладились использованием ряда особенностей ES6+, при написании нашх React компонентов. Позвольте мне остановиться на тех моментах, когда новые возможности языка могут повлиять на то как вы пишите React приложения, и сделает этот процесс легче и веселее, чем когда-либо.
Классы
До сих пор наиболее заметным из видимых изменений в том, как мы пишем наши React компоненты, используя ES6+ является то, что мы решили использовать синтаксис определения класса. Вместо того чтобы использовать метод React.createClass для определения компонента, мы можем определить настоящий ES6 класс, который расширяет класс React.Component:
class Photo extends React.Component { render() { return <img alt={this.props.caption} src={this.props.src} />; } }
Вы сразу же вы заметите небольшое различие — вам становится доступным более лаконичный синтаксис определения класса:
// The ES5 way var Photo = React.createClass({ handleDoubleTap: function(e) { … }, render: function() { … }, });
// The ES6+ way class Photo extends React.Component { handleDoubleTap(e) { … } render() { … } }
Стоит отметить, что мы отбросили две скобки и завершающую точку с запятой, а для каждого объявленного метода мы опускаем двоеточие, ключевое слово function и запятую.
Все методы жизненного цикла компонента, кроме одного могут быть определены, как можно было бы ожидать, с использованием нового синтаксиса определения классов. Конструктор класса в настоящее время выступает в роли ранее используемого метода componentWillMount:
// 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 } }
Инициализаторы свойств
В мире классов ES6+, типы свойств и значения по умолчанию могут существовать как статические свойства этого класса. Эти переменные, а также начальное состояние компонента, могут быть определены с использованием ES7 инициализаторов свойств:
// 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, } }
Инициализаторы свойств ES7 работают внутри конструктора класса, где this относится к текущему экземпляру класса перед его созданием. Благодаря этому, начальное состояние компонента может зависить от this.props. Примечательно, что мы больше не должны определять значения props по умолчанию и начальное состояние объекта в терминах getter функции.
Arrow функции
Метод React.createClass используется для выполнения некоторых дополнительных работ по привязке к методам экземпляра компонента, чтобы убедиться, что внутри них, ключевое слово this будет относиться к экземпляру компонента.
// 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}); }, });
Так как мы не связаны использованием метода React.createClass, при определении компонентов синтаксисом классов ES6+, казалось бы, что нам нужно вручную привязать методы экземпляра, туда где мы хотим их использовать:
// 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}); } }
К счастью, путем объединения двух возможностей ES6+ – arrow функции и инициализаторы свойств – отказ от привязки к экземпляру компонента становится очень легким:
class PostInfo extends React.Component { handleOptionsButtonClick = (e) => { this.setState({showOptionsModal: true}); } }
Тело ES6 arrow функций использует то же лексическое this как и код, который их окружает. Это позволяет нам достичь желаемого результата из-за того, что ES7 инициализаторы свойств находятся в области видимости. Загляните под капот, чтобы понять почему это работает.
Динамические имена свойств и шаблоные строки
Одним из усовершенствований литералов объектов включает в себя возможность назначать производные имена свойствам. Изначально мы могли бы сделать что-то подобное для установки некоторой части состояния компонента:
var Form = React.createClass({ onChange: function(inputName, e) { var stateToSet = {}; stateToSet[inputName + 'Value'] = e.target.value; this.setState(stateToSet); }, });
Теперь у нас есть возможность создавать объекты, в которых имена свойств определяются выражением JavaScript во время выполнения. Здесь мы используем шаблонные строки, для того что-бы определить, какое свойство установить в состоянии компонента:
class Form extends React.Component { onChange(inputName, e) { this.setState({ [`${inputName}Value`]: e.target.value, }); } }
Деструктуризация и распространение атрибутов
Часто при создании компонентов, мы могли бы передать большинство свойств родительского компонента к дочернему компоненту, но не все из них. В сочетании ES6+ деструктурирования и распространения атрибутов JSX, это становится возможным без плясок с бубном:
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> ); } }
Так же мы можем сочетать JSX распространение атрибутов с регулярными атрибутами, пользуясь простым правилом приоритета для реализации переопределения значений и установки значений атрибута по умолчанию. Этот элемент получит переопределеное значение атрибута className, даже если свойство className существует в this.props:
<div {...this.props} className="override"> … </div>
Атрибут className этого элемента по умолчанию имеет значение «base», если не существует свойства className в this.props чтобы переопределить его:
<div className="base" {...this.props}> … </div>
Спасибо за чтение
Я надеюсь что вам, так же как нам, понравится использовать возможности языка ES6+ для написания React кода. Спасибо моим коллегам за их вклад в эту статью, и особая благодарность команде Babel за то что они делают будущее доступным для всех нас, уже сегодня.
ссылка на оригинал статьи http://habrahabr.ru/post/262183/
Добавить комментарий