Перевод статьи, посвящённой использованию ReactJS для создания фронтенда.
React — отличный инструмент для реализации простых интерактивных веб-сайтов. Но насколько он применим в сложных фронтенд-проектах? Работает ли он там столь же хорошо?
В этой статье мы рассмотрим некоторые проблемы, с которыми можно столкнуться при использовании React во время веб-разработки. Также вы узнаете, почему автор статьи решил разработать новый фреймворк на Scala, благодаря которому удалось сократить количество строк кода с 30 тысяч (на React) до одной тысячи.
Ключевые моменты
- Компоненты React трудно использовать повторно в сложных веб-проектах.
- Алгоритм Virtual DOM в React медленный и неточный.
- HTML-шаблоны React не являются ни полными, ни мощными.
- React требует сложного асинхронного программирования при общении с сервером.
- Binding.scala содержит меньше концепций, но больше функций. Перспективный Binding.scala решает сложные проблемы, которые React решить не может.
Предпосылки
Многим фреймворк React кажется более простым и удобным по сравнению с AngularJS. Одной из самых полезных его функций является связывание данных (data binding). Оно позволяет сопоставить источники данных с элементами веб-страниц, что предоставляет удобный способ реализации простых интерактивных веб-сайтов.
Однако возможны ситуации, в которых React не может решать запутанные проблемы так же легко, как простые. Если поэкспериментировать с TodoMVC, то окажется, что приложение на фреймворке Binding.scala содержит всего 154 строки кода по сравнению с 488 строками на React.
Дальше мы рассмотрим четыре проблемы React и как их решает Binding.scala.
Проблема 1: компоненты React трудно повторно использовать в сложных интерактивных веб-проектах
Минимальным блоком для повторного использования в React является компонент (React.Component
). Он более лёгкий, чем Controller
и View
в AngularJS. От веб-разработчика требуется лишь реализация функции render
, которая транслирует свойства (props) и состояние (state) компонента в HTML-элементы.
Такой легкий компонент очень удобен при создании простых веб-страниц. Однако, когда требуется взаимодействие между несколькими компонентами, неизбежна передача функций обратного вызова (callback functions) в качестве параметра. В частности, для веб-страниц со сложными структурами приходится использовать десятки взаимосвязанных компонентов, в которых коллбэки передаются от родителей к потомкам из слоя в слой. Единственным результатом применения фреймворка React в таких сложных интерактивных веб-проектах будет то, что код станет слишком беспорядочным и трудноподдерживаемым.
Проблема 2. Virtual DOM в React является медленным и неточным
Алгоритм рендеринга в React использует Virtual DOM.
Разработчик обязан предоставить функцию render
, которая создает виртуальный DOM, используя свойства и состояние компонента. А React на основе этого виртуального DOM конструирует реальный.
При изменении состояния React вновь вызывает функцию render и строит новый Virtual DOM. Затем он анализирует различия между старой и новой версией виртуального DOM и применяет их к реальному DOM.
У этого процесса есть два недостатка:
- 1. Независимо от того, что изменилось в состоянии, функции рендеринга всегда будут генерировать новые полные виртуальные DOM. Если функция render сложна, то вычислительные ресурсы тратятся впустую.
- 2. Сравнение двух версий DOM медленное и подвержено ошибкам. Например, если вы хотите вставить элемент
li
в началоul
, то React ошибочно решит, что вы модифицировали все компонентыli
вul
и добавили одинli
в конце.
Поскольку две версии виртуального DOM независимы друг от друга, React не имеет представления о том, что происходит на самом деле. Он случайным образом угадывает произошедшие изменения, основываясь на обоих DOM. Этот алгоритм очень медленный и неточный. Веб-разработчики вынуждены использовать свойство key, а также методы shouldComponentUpdate
и componentWillUpdate
, чтобы помочь фреймворку угадать правильно.
Проблема 3. HTML-шаблоны React не являются ни полными, ни мощными
Для разработки HTML-шаблонов React поддерживает JSX.
Теоретически, фронтенд-разработчики могут превратить статический HTML в динамическую веб-страницу, просто скопировав HTML в JSX-файлы и добавив немного дополнительного кода. Действительно, React больше подходит для повторного использования HTML-шаблонов по сравнению с другими фреймворками, такими как Cycle.js, Widok и ScalaTags.
К сожалению, поддержка HTML в React является неполной. Разработчик должен вручную заменить class
на classname
, а for на htmlFor
. Кроме того, синтаксис встроенных стилей необходимо поменять с CSS на JSON. И хотя веб-разработчики могут копипастить HTML в код, это всё равно требуется много времени и усилий. Таким образом, нельзя сказать, что React превосходит Cycle.js, Widok или ScalaTags.
Для проверки валидности данных React предоставляет механизм propTypes
. Но этот механизм полон дыр. Даже используя propType
React сможет найти ошибки только во время работы программы, а не во время компиляции.
React также не способен найти ошибки в именах. Например, если написать onclick
вместо onClick
, то сообщения об ошибке не будет, но программа завершится сбоем. На поиски таких бессмысленных ошибок разработчики обычно тратят очень много времени и энергии.
Проблема 4: React требует сложного асинхронного программирования при общении с сервером
Рассмотрим работу React с сервером в терминах шаблона Model-View-ViewModel. Веб-разработчику нужно реализовать слой доступа к базе данных (Model), state
в качестве ViewModel и функцию render
в качестве View
. Модель обеспечивает доступ к API бэкенда и устанавливает state
(ViewModel
), используя промисы (Promise and fetch API). Затем render
(View
) обеспечивает визуализацию ViewModel
на веб-страницах.
Во время этого процесса фронтенд-программистам необходимо разработать асинхронную процедуру, состоящую из массива замыканий. Код такой процедуры неизбежно становится запутанным и склонным к ошибкам. Даже если очень тщательно следить за всевозможными асинхронными событиями, процесс отладки и сопровождения такой программы чрезвычайно усложняется.
Выводы
Binding.scala в некотором роде кажется похожим на React. Но лежащий в его основе механизм полностью отличается от React и Widok, он проще и универсальнее. Binding.scala гибче и мощнее, чем React. Мы можем использовать Binding.scala для решения сложных проблем, которые React решить не может.
Кроме четырех аспектов, упомянутых выше, есть и довольно значительная проблема управления состоянием в React. Если для управления состоянием использовать стороннюю библиотеку, такую как Redux, то структура приложения станет еще более запутанной, а количество слоев увеличится.
Для сравнения, Binding.scala описывает сложное состояние, используя тот же механизм связывания данных (data-binding), что и для рендеринга веб-страницы. И нет никакой надобности в сторонних библиотеках для обеспечения таких функций, как клиент-серверное взаимодействие, управление состоянием и URL-диспетчеризация.
Различия между Binding.scala и React:
Binding.scala | React | ||
---|---|---|---|
Повторное использование | Минимальный блок для повторного использования | Метод | Компонент |
Уровень сложности повторного использования | Возможность повторного использования независимо от интерактивных или статических компонентов | Простота повторного использования в статических компонентах, но трудно использовать в интерактивных компонентах | |
Алгоритм рендеринга веб-страницы | Алгоритм | Точная привязка данных | Virtual DOM |
Производительность | Высокая | Низкая | |
Корректируемость | Автоматически обеспечивает правильность | Необходимо вручную настроить ключевые атрибуты | |
HTML | Синтаксис | Scala XML | JSX |
Поддерживает синтаксис HTML или XHTML? | Полностью поддерживает XHTML | Частично поддерживает, не может компилировать нормальный XHTML. Разработчики должны вручную заменить атрибуты class и for на className и htmlFor , а также изменить синтаксис стилей с CSS на JSON |
|
Как проверяется синтаксис | Проверяется автоматически при компиляции | Выполняется через propTypes , но не может найти очевидные орфографические ошибки |
|
Взаимодействие с сервером | Механизм | Автоматическая удаленная привязка данных | MVVM + асинхронное программирование |
Уровень трудности реализации | Легко | Тяжело | |
Другое | URL-диспетчеризация | Поддерживает URL-адреса как обычные связанные переменные, не требует сторонней библиотеки | Не поддерживает, требуется сторонняя библиотека react-router |
Полнота функциональности | Полное решение для фронтенд-разработки | Содержит только функциональность слоя View. Требует сторонние библиотеки для полной фронтенд- разработки | |
Кривая обучения | API относительно прост. Легок для понимания даже теми, кто никогда не использовал Scala | Удобно. Но чрезвычайно трудно изучить стороннюю библиотеку, которая используется для компенсации слабых сторон фреймворка |
Ещё недавно среди представителей сообщества Scala.js самым популярным фронтенд-фреймворком был Widok. Но вскоре это место занял Binding.scala. Даже автор Widok Тим Нирадзик (Tim Nieradzik), не смог удержаться от похвалы и назвал Binding.scala наиболее перспективным фрейворком для рендеринга HTML5. Awesome Scala, сравнивая Binding.scala с конкурентами, также приходит к выводу, что этот фреймворк сейчас популярнее, чем Udash и Widok
Продолжение следует. Мы будем переводить и публиковать следующие части этого цикла статей по мере их появления.
Автор: NIX Solutions