Как работают реактивные фреймворки


Пробежимся коротко о том, как работают React, Vue и Angular на примере создания своего реактивного фреймворка

Начнём с простого

Первое, с чего начинается документация любого реактивного фреймворка — простой пример с текстовым полем, параграфом и переменной, которая объединяет (синхронизирует) текстовые значения в этих элементах.

Это реализуется проще простого: создаётся JavaScript объект, где наша переменная со значением является свойством объекта. На это свойство создаются геттеры и сеттеры. Каждый геттер в большнитсве случаев тупо возвращает наше значение и ничего с ним не делает. Сеттером же является функиция, которая берёт элемент из DOM и меняет там значение.

Теперь, для того, чтобы изменить значение в блоке, мы просто меняем значение свойства у нашего объекта. Согласитесь, чем-то напоминает первые уроки из Vue.

See the Pen HowToReact / Реактивность by Alexander Aleokheen (@aleokheen) on CodePen.

Теперь директивы

В любом MVC фреймворке есть такая штука, как директивы. Это такие %username% штуки, куда скрипт вставляет информацию.

Директивы сами по себе работают очень просто; особенно - если не требуется реактивность. Достаточно пройтись регулярным выражением и заменить все %<название_поля>% на значения переменных.

В реактивных фреймворках всё сложнее. После первого рендеринга страницы (когда все директивы заменены на значения переменных), мы уже не можем искать директивы регулярным выражением, т.к. они уже все исчезли.

Здесь начинается одна из сложнейших, важнейших и основательных вещей любого реактивного фреймворка - работа с DOM. Чтобы понять представленный пример кода, необходимо знать особенности работы с браузерским DOM (в частности знание того, что такое HTML- или текстовая нода, как менять HTML-элементы местами и т.д.)

В представленном примере мы сделаем автоматическое создание геттеров и сеттеров для нашего объекта. Работу с DOM вынесем в отдельную функцию и будем вызывать её при изменении полей и при начальном рендереринге страницы.

Чтобы заменить директивы на нужные нам поля и, более того, сделать это всё реактивным, нам потребуется взять все текстовые ноды страницы, вырезать из них директивы и сделать их отдельными нодами. Далее мы просто меняем весь текст в самой ноде при изменении полей. Регулярные выражения используются только один раз при парсинге нод

See the Pen HotwoReact / 2 by Alexander Aleokheen (@aleokheen) on CodePen.

Работа с массивами

Увы, геттеры и сеттеры не умеют обрабатывать изменения в дочерних массивах и объектах. Если дело касается массивов, в JavaScript можно добавить геттеры/сеттеры в массив при помощи Proxy. Такое поможет при изменении существующих элементов массивов, а вот на методы push, unshift, pop и т.п такая штука не реагирует.

Что же делать в такой ситуации? Банально переписываем эти методы у массивов. Не обязательно трогать прототип класса Array, достаточно прописать локальные методы push/pop/unshift/shift в какой-то конкретный массив и по каждому методу вызывать необходимые хуки. Таким образом массив вновь становится реактивным.

Когда вы прогоняете ваш объект и автоматически ставите геттеры/сеттеры, вы можете сделать проверку на тип данных и, если это массив, прописать ему кастомные методы push/pop/unshift/shift. Если это объект, вызываете функцию рекурсивно для каждого дочернего объекта.

Здесь пример упрощён. Нет текстовых директив и объекта с геттерами/сеттерами. Здесь показан самый сок, который не запутает вас и поможет понять, как многое можно творить, если хорошо знать JavaScript

See the Pen LYNGJJY by Alexander Aleokheen (@aleokheen) on CodePen.

Условные операторы (v-if)

Показ-скрытые элементов - одна из самых легчайших вещей, которую можно реализовать в реактивном фреймворке.

В представленном примере есть три текстовых блока. Два из них спрятаны (у них не стоит display: none; их вообще нет в DOM).

Когда мы нажимаем на кнопку, чтобы скрыть блок, мы просто заменяем его ноду на комментарий (или на что угодно), а чтобы показать блок - меняем ноду с комментарием на сам блок обратно.

See the Pen HowToReact / 3 by Alexander Aleokheen (@aleokheen) on CodePen.

Заключение

Представленные выше примеры предоставлены для того, чтобы немного расширить ваше представление о языке JavaScript и работе с браузерским DOM. Любой реактивный фреймворк работает ровно по предоставленным выше принципам, но, увы, не всё так просто, как может показаться.

Разработать реактивный фреймворк действительно сложно. Если у меня на создание этого лендинга вместе со всеми примерами ушёл ровно день, то на создание того же React или Vue уйдёт гораздо больше времени. В любом популярном реактивном фреймворке кроме основных его возможностей, продуманы также оптимизация, удобство работы в больших проектах (когда много кода), поддержка широким кругом браузеров и т.д.

Реактивные фреймворки лучше всего подходят для написания именно веб-приложений, где страницы полностью динамические и зависят от разных условий. Если вы делаете какой-нибудь лендинг или визитку, лучше всего воспользоваться чистым JavaScript. Кстати данная страница написана на чистых HTML/CSS/JS без единой библиотеки

Об авторе

Александр Алёхин Александр Алёхин Веб-разработчик (MERN)