Pull to refresh

Можно ли обойтись без jsx и зачем?

Reading time 3 min
Views 15K

Я уверен, большинство из вас, кто использует react используют jsx. Благодаря своему лаконичному синтаксису jsx улучшает читабельность шаблонов. Сравните:


render() {
    return React.createElement('div', { className: 'block'}, 'Text of block');
}
// vs
render() {
    return <div className='block'>
        Text of block
    </div>;
}

Второй вариант даже в таком простом примере выглядит намного понятнее. Если усложнить пример, то разница будет еще очевиднее.


Чем плох jsx


Все бы хорошо, если бы jsx был бы стандартной возможностью javascript, но это не так. Для работы с jsx вам потребуется транспилятор. Решив использовать jsx вы навечно становитесь зависимы от транспиляции. Еще недавно, такая зависимость никого не пугала, так как для использования новых возможностей из ecmascript 2015 вам в любом случае необходим транспилятор. Но все меняется, уровень поддержки es6 близок к 100%


По крайней мере, в develop-окружении уже можно избавляться от транспиляции. Представляете, какие возможности это открывает? Не нужно при дебаге ковыряться в выходе babel, который многое изменил, не нужны source map, после изменения файла нет необходимости ждать, пока закончится пересборка. И jsx в данном случае будет главной помехой… Есть ли альтернативы jsx?


Альтернативы jsx


Стандарт ecmascript 2015 определяет тегированные шаблонные строки. Пример, выше можно переписать так:


render() {
    return es6x `<div className='block'>
        Text of block
    </div>`;
}

Более сложный пример:


import Input from './input';

render() {
    return <div className='block'>
        <Input name='name1'
            value={this.props.value}
            {...this.props.inputProps}
            checked
        />
        {this.props.items.map(item => <span {...item.props}>{item.text}</span>}
    </div>;
}
// преобразуется в:
render() {
    return es6x `<div className='block'>
        <${Input} name='name1'
            value=${this.props.value}
            ${this.props.inputProps}
            checked
        />
        ${this.props.items.map(item => es6x `<span ${item.props}>${item.text}</span>`)}
    </div>`;
}

Как подключить


npm install --save es6x

Пакет es6x поддерживает разные движки. Среди них react, hyperscript (h), а также (по умолчанию) универсальный вывод в json вида:


{
    tag: 'div',
    attrs: {
        className: 'block'
    },
    children: ['Text of block']
}

Чтобы использовать совместно с react нужно указать метод вывода перед первым вызовом (в одном месте проекта):


import React from 'react';
import es6x from 'es6x';

es6x.setOutputMethod(React.createElement);

Особенности пакета es6x


  • размер в сжатом виде около 2 кб
  • шаблоны кешируются — во время первого исполнения создается кеш, который используется при повторных вызовах
  • решена проблема пробельных символов внутри шаблонов, которой страдает jsx:

return <div>
    {'some text'}
    {' '}
    <b>strong</b>
    {' '}
    <i>emphase</i>
</div>

В примере выше, в jsx требуется добавлять уродливую кострукцию {' '} между словами "text", "strong" и "emphase" а в es6x этого не потребуется:


return es6x `<div>
   ${'some text'}
   <b>strong</b>
   <i>emphase</i>
</div>`;

Производительность


es6x поддерживает кеширование, благодаря чему, при повторном вызове с тем же шаблоном не происходит парсинга и вызов происходит намного быстрее. Повторный вызов по результатам тестирования в 10 раз быстрее первого (в случае универсального парсинга в json, в случае парсинга для react разница меньше — менее чем в 2 раза). Так же я производил сравнение с конкурентным пакетом t7 при парсинге для react. Результаты:


jsx-выход: 15683 ops/sec ±1%
es6x: 11187 ops/sec ±1%
t7: 10253 ops/sec ±1% (не поддерживает многих плюшек jsx)


То есть падение производительности около 30%. Что оказалось меньше, чем я ожидал. Объясняется тем, что метод createElement достаточно тяжелый.


Пользуйтесь, сообщайте мне о багах. Всем спасибо за внимание.

Tags:
Hubs:
+22
Comments 79
Comments Comments 79

Articles