slonoed

Использование r-dom

2019 M03 10 • ☕️ 7 min readRead in English

r-dom — это небольшая обёртка над функцией React.createElement, позволяющая писать React компоненты без JSX.

Я использую эту библиотеку уже больше года на одном из проектов и хочу рассказать, почему мне нравится с ней работать.


Сама библиотека очень маленькая: всего 96 строк. Она использует React.createElement и добавляет несколько полезных фич. Библиотека никак не меняет подход к построению React приложения. Можно (но не нужно) даже смешивать r-dom и JSX в одном компоненте.

Пример использования

Я покажу, как пользоваться библиотекой. Если вы уже знакомы с JSX, то трудностей никаких не будет.

Для простых тегов используется форма r[tag]([properties], [children])

r.span(Hello)
// эквивалентно
<span>hello</span>

Если нужно передать несколько потомков, то их необходимо завернуть в массив

r.span(['Hello, ', name])
// эквивалентно
<span>Hello, {name}</span>

Свойства (props) передаются первым аргументом, если необходимо

r.a({href: '/page'}, 'home')
// эквивалентно
<a href="/page">home</a>

Компоненты используют форму r(component, [properties], [children])

r(Alert, 'Danger!')
// эквивалентно
<Alert>Danger!</Alert>

Почему просто не использовать JSX?

JSX сейчас является стандартным решением. Код с применением JSX встречается в документации, руководствах и проектах с открытым кодом. Скорее всего, для следующего вашего проекта JSX будет правильным выбором.

Зачем использовать r-dom

Когда React только набирал популярность, было много споров по поводу использования JSX.

У меня нет цели начать такой спор. Вместо этого я хочу рассказать, почему и как я использую чистый JS для написания React компонентов и какие плюсы это может дать.

JavaScript

Один из плюсов заключается в выгоде использования JavaScript. Когда вы используете чистый JS, то получаете полную поддержку редактора, сниппетов, рефакторинга и прочего.

Поддерка редактора не является значимым преимуществом, если вы используете современные IDE. Webstorm, например, имеет очень хорошую поддержку JSX.

Отсутствие смешения языков

Этот пункт довольно субъективный. Я нахожу ненужную сложность в необходимости оперировать двумя совершенно разными синтаксисами.

r.div(
  {style: {color: 'red'}},
  users.map(user => r.span({key: user.id}, user.name))
)

// или

<div style={{color: 'red'}}>
  {users.map(user => <span key={user.id)>{user.name}</span>}
</div>

Проблема с пробелом между элементами

При использовании JSX нужно не забывать указывать знак пробела между инлайн элементами.

r.div([
  r.a('first),
  ' ',
  r.a('second')
])

// или

<div>
    <a>first</a>{' '}
    <a>second</a>
</div>

Пропуск рендера по условию

Пожалуй, это моя любимая фича в r-dom. Можно пропустить рендер элемента, установив ему специальное свойство isRendered в значение false. Это делает код более читаемым.

r.div(
  r.span({isRendered: user.credits < 0}, 'You have no credits')
)

// или

<div>
  {user.credits < 0 && <span>You have no credits</span>}
</div>

Комментарии

Тут без комментариев

r.div([
  r.label('User email'),
  // Прекрасный однострочный комментарий
  r.input({type: 'email'})
])

// vs

<div>
  <label>User email</label>
  {/* Гадкий утёнок */}
  <input type="email"/>
</div>

Необходимость следить за закрывающим тегом

При работе с JSX, если нужно заменить компонент, то нужно изменить оба тега: открывающий и закрывающий.

<Component>
  Длинный список компонентов внутри
<Component>

В случае r-dom нужно заменить только один.

r(Component, [
  'Длинный список компонентов внутри'
])

Ещё мне надоедает переключаться между <Component/> и <Component></Children>, когда нужно добавить потомков, потому что Prettier по умолчанию сворачивает тег без потомков в одинарный.

Проблема закрывающего тега уходит при хорошей поддержке JSX вашим редактором.

classSet

У r-dom есть встроенная поддержка classnames.

r.div(
  {
    classSet: {
      alert: credints < 0,
    }
  },
  ['You have ', credits, ' credits']
)

Я не пользуюсь этой возможностью часто, так как в моём проекте используется CSS-in-JS решение, но я вижу преимущество встроенной работы с CSS классами.

Бонус: минус r-dom

Одна вещь, которая меня раздражает: в некоторых случаях r-dom воспринимает потомка как props.

function Component() {
  const text = r.strong('Бу!')
  return r.div(text) // ошибка!
}

В коде выше, переменная text является React элементом, но библиотека считает, что ей передали объект props. Решить это можно, используя массив.

function Component() {
  const text = r.strong('Boo!')
  return r.div([text]) // Работает.
}

Заключение

Библиотекой я начал пользоваться, когда получил в наследство проект, использующий её. Непривычная по началу, она стала для меня крайне удобным инструментом. То же я наблюдаю и у других разработчиков. Мой следующий проект, который я буду делать для себя, скорее всего, будет использовать r-dom вместо JSX. При этом я не хочу сказать, что вам нужно обязательно бросать JSX, но предлагаю посмотреть вокруг уже используемых решений.


Если у вас есть вопросы или вы хотите обсудить текст, то напишите мне в twitter.