Если вы используете библиотеку React, то наверняка используете и jsx. Конечно, это не обязательно, и можно писать только js, используя

Принцип действия плагина прост. Плагин преобразует jsx-компоненты, такие как
После обработки плагином, получим:
Теперь подробнее о
Атрибут
Преобразуется в:
Также, как видно из примеров выше, в цикле доступен номер элемента в переменной
Для корректной работы React, каждый элемент в массивах должен иметь атрибут
.babelrc
Будет преобразовано в:
Это просто альтернатива для синтаксиса:
Основная задача сделать всё в едином, html-подобном стиле. Есть два атрибута: либо
Преобразуется в:
Довольно специфическое выражение. Превращает содержимое в стрелочную функцию:
Преобразуется в:
Соответственно, внутри
На выходе получим:
Предположим, есть такой компонент:
For будет преобразован в выражение, возвращающее массив. Однако метод
Но делать это не обязательно. Так как плагин сам обернёт массив в react-элемент. По умолчанию, это
Также можно отключить автоматическое обёртывание, используя значение параметра
Допустим, что в проекте уже есть компонент
Или можно переименовать выражение, чтобы в jsx использовать другое имя, например,
Код пишется для людей, поэтому так важна его читаемость. И читаемость является главной проблемой jsx, а конкретно — перемешивание двух языков. Как видно, эта проблема решается, и решается она благодаря гибкости jsx в возможности вставлять javascript-код.
P.S. Автору было бы приятно получить звездочек на github, в качестве благодарности за работу.
React.createElement, но с jsx получится гораздо лаконичнее, что повышает читаемость. И всё замечательно до появления первой необходимости вывести данные в цикле. В jsx циклы не предусмотрены. Зато предусмотрена вставка js-кода. И тут вновь возникает вопрос читаемости, но теперь она значительно ухудшается. Возникает ситуация, когда в js-коде пишется html, в котором пишется js-код с html. Конечно, можно выделить html в отдельную функцию. Но тогда html будет появляться в коде то тут, то там. А хотелось бы локализовать всё в одном месте. К счастью, в современном javascript почти для любой проблемы, есть решение в виде библиотеки или плагина. Выше обозначенную проблему легко решает плагин для babel transform-react-statements.
Цикл For
Принцип действия плагина прост. Плагин преобразует jsx-компоненты, такие как
<For/>, в js-код. Допустим есть вот такой компонент:const MyComponent = props => <ul> <For each="item" in={props.items}> <li key={item.id}> {item.text} </li> </For> </ul>
После обработки плагином, получим:
var _this = this; const MyComponent = props => <ul> {Array.prototype.map.call(props.items, function (item, index) { return <li key={item.id}> {item.text} </li>; }, _this)} </ul>;
Теперь подробнее о
For. В первую очередь атрибут in. Это обязательный атрибут, в котором обозначается способ получения итерируемого объекта (например, переменная). Значение должно быть выражением, т.е. заключено в фигурные скобки.Атрибут
each задает имя переменной для каждого элемента массива. Он не является обязательным. В случае его отсутствия, элементы массива будут передаваться в качестве spread-атрибута.<div> <For in={items}> <Item /> </For> </div>
Преобразуется в:
<div> {Array.prototype.map.call(items, function (value, index) { return <Item {...value} />; }, this)} </div>
Также, как видно из примеров выше, в цикле доступен номер элемента в переменной
index. Переменную можно переименовать с помощью атрибута counter:<For each="row" counter="rowIndex" in={rows}> <div key={`row-${rowIndex}` className="row"> <For each="cell" counter="cellIndex" in="row"> <div key={`cell-${cellIndex}`} className="ceil"> { cell.content } </div> </For> </div> </For>
Атрибут key
Для корректной работы React, каждый элемент в массивах должен иметь атрибут
key. Его можно указать очевидно, как в примере выше. Другой способ — использовать атрибут key-is. Это может немного улучшить читаемость. Также можно указать keyIs в параметрах плагина. Тогда key не нужно будет писать в шаблоне — логика его получения уходит в бизнес-логику..babelrc
{ plugins: [["transform-react-statements", { keyIs: "id" }]] }
<div> <For each="item" in={array}> <div>{ item.value }</div> </For> <For each="item" in={array} key-is="someKey"> <div>{ item.value }</div> </For> <For each="item" in={array}> <div key={item.getKey()}>{ item.value }</div> </For> </div>
Будет преобразовано в:
<div> {Array.prototype.map.call(array, function (item) { // key берется из параметров плагина return <div key={item.id}>{item.value}</div>; }, this)} {Array.prototype.map.call(array, function (item) { // key - из атрибута <For /> return <div key={item.someKey}>{item.value}</div>; }, this)} {Array.prototype.map.call(array, function (item) { // стандартный для React способ return <div key={item.getKey()} key={item.id}>{item.value}</div>; }, this)} </div>;
Условие If
Это просто альтернатива для синтаксиса:
<div> { condition && <Component /> } </div>
Основная задача сделать всё в едином, html-подобном стиле. Есть два атрибута: либо
true, либо false, проверяющие условие на истинность или ложность соответственно. Для нескольких дочерних элементов, условие будет применяться к каждому из них:<div> <If false={someCondition}> <div> Текст 1 </div> <div> Текст 2 </div> </If> </div>
Преобразуется в:
<div> { !someCondition && <div> Текст 1 </div> } { !someCondition && <div> Текст 2 </div> } </div>
Switch..Case..Default
Switch ведёт себя также, как и в javascript. У компонента Switch есть атрибут value, значение которого должно быть выражением в фигурных скобках, и дочерние компоненты Case, со своими атрибутами value. Если значение не соответствует ни одному из значений Case, выводится блок Default. Если блок Default отсутствует, возвращается null.<div> <Switch value={x}> <Case value={“foo”}> <div> Text 1 </div> </Case> <Case value="bar"> <div> Text 2 </div> </Case> <Case value={1}> <div> Text 3 </div> </Case> <Default> <div> Default text </div> </Default> </Switch> </div>
Component
Довольно специфическое выражение. Превращает содержимое в стрелочную функцию:
<Component> <div> text </div> </Component>
Преобразуется в:
props => <div> text </div>;
Соответственно, внутри
<Component/> доступна переменная props, которую можно переопределить через атрибут props:<Component props="item"> <div {...item} /> </Component>
На выходе получим:
item => <div {...item} />;
Автоматическое обертывание
Предположим, есть такой компонент:
class MyComponent extends React.Component { render() { return <For each="item" in={props.items}> <div key={item.id}> {item.text} </div> </For> } }
For будет преобразован в выражение, возвращающее массив. Однако метод
render должен вернуть React-элемент. Для того, чтобы использовать такой компонент, цикл нужно обернуть в элемент. Например так:class MyComponent extends React.Component { render() { return <div> <For each="item" in={props.items}> <div key={item.id}> {item.text} </div> </For> </div> } }
Но делать это не обязательно. Так как плагин сам обернёт массив в react-элемент. По умолчанию, это
<span />. Такое поведение можно изменить, указав параметр wrapper в настройках плагина:{ plugins: [["transform-react-statements", { wrapper: '<div class=”wrapper” />' }]] }
Также можно отключить автоматическое обёртывание, используя значение параметра
no-wrap:{ plugins: [["transform-react-statements", { wrapper: "no-wrap" }]] }
Отключение и переименование выражений
Допустим, что в проекте уже есть компонент
<If />, который вполне справляется со своей задачей. Тогда его можно отключить с помощью параметра disabled:{ plugins: [["transform-react-statements", { disabled: ["If"]}]] }
Или можно переименовать выражение, чтобы в jsx использовать другое имя, например,
IfStatement:{ plugins: [["transform-react-statements", { rename: { "If": "IfStatement" } }]] }
Код пишется для людей, поэтому так важна его читаемость. И читаемость является главной проблемой jsx, а конкретно — перемешивание двух языков. Как видно, эта проблема решается, и решается она благодаря гибкости jsx в возможности вставлять javascript-код.
P.S. Автору было бы приятно получить звездочек на github, в качестве благодарности за работу.