Использование r-dom
March 10, 2019 • ☕️ 7 min read • Read 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, но предлагаю посмотреть вокруг уже используемых решений.