DEV Community

Arif Balaev
Arif Balaev

Posted on • Edited on

Почему React не реактивен?

Хотя в названии библиотеки React присутствует слово «РЕАКТ», её связь с парадигмой реактивного программирования куда интереснее, чем кажется на первый взгляд. Давайте разберемся, является ли React реактивным в классическом понимании этого слова.

Что такое реактивное программирование?

Для начала, что такое «реактивность»? В широком смысле, это парадигма программирования, ориентированная на автоматическое распространение изменений. Самый простой пример — электронная таблица. Вы меняете значение в одной ячейке, и все ячейки, которые от неё зависят, мгновенно пересчитываются. Им не нужно давать команду «обновись!», они сами реагируют на изменение источника данных.

В программировании эта идея чаще всего реализуется через потоки данных (streams) — асинхронные последовательности событий, которые происходят во времени. На эти потоки можно подписываться и реагировать на них.

Представьте ленту новостей в приложении. Новостной сервер — это Observable (наблюдаемый источник), который испускает события (новые статьи). Вы, как пользователь, — это Observer (наблюдатель), который подписан на этот источник и получает обновления, как только они появляются. Источник «проталкивает» (push) данные к наблюдателю. Это классическая, push-based модель реактивности, которую популяризировали такие библиотеки, как RxJS.

Ключевая особенность этой модели — полный контроль над потоком. События можно фильтровать (filter), преобразовывать (map) и даже группировать по времени (например, оператор bufferTime в RxJS может собрать все события за 2 секунды и выдать их одной пачкой).

Как работает React?

React построен вокруг простой идеи: ваш UI — это функция от вашего состояния (state). Изменилось состояние — изменился UI.

UI = f(state)

Событие из внешнего мира (клик мыши, ответ от сервера) вызывает изменение состояния через setState. Это, в свою очередь, запускает процесс обновления UI.

Внешне это выглядит как та самая реакция на изменения. Но дьявол, как всегда, в деталях. Нюанс заключается в том, КАК React решает обновить UI.

Когда вы вызываете setState, React не бросается сломя голову перерисовывать DOM. Вместо этого он планирует обновление. Он как бы ставит себе пометку: «Ага, состояние изменилось. Скоро нужно будет обновить интерфейс». Если вы вызовете setState несколько раз подряд в одном и том же обработчике, React окажется достаточно умён, чтобы объединить (сбатчить) их все в одно-единственное обновление.

Это фундаментальное отличие. В отличие от классической push-модели, где данные проталкиваются к подписчику, модель React можно назвать pull-based (основанной на запросе). React получает уведомление об изменении, но сам решает, когда запросить (pull) новое состояние и как наиболее эффективно обновить UI на его основе.

Так реактивен ли React?

Да, но он реализует свою, особую модель реактивности.

React реактивен в своей декларативной сути. Вы описываете, как должен выглядеть UI для определённого состояния, и доверяете React синхронизировать реальный DOM с этим описанием. В этом смысле он полностью соответствует широкому определению реактивности — UI автоматически реагирует на изменения данных.

Однако React не является «реактивным» в классическом, потоковом смысле, как RxJS. Он не предоставляет из коробки мощных инструментов для управления потоками событий. Его реактивность узко специализирована и нацелена на одну задачу: эффективное обновление дерева компонентов.

Пакетная обработка обновлений (batching) — это не то, что делает React «нереактивным». Как мы помним из примера с bufferTime в RxJS, управление потоком и группировка событий — это часть инструментария реактивных систем. Это лишь подчёркивает, что React выбрал конкретную стратегию управления изменениями, поставив во главу угла производительность и предсказуемость рендеринга.

Итог

Разобравшись в моделях реактивности, мы можем сделать вывод: React — это реактивная библиотека, но её реактивность не та, что в классических push-библиотеках вроде RxJS.

React использует pull-based модель с планированием обновлений, идеально заточенную под задачи построения пользовательских интерфейсов. Именно поэтому для сложных сценариев управления асинхронными потоками (например, при работе с WebSockets или сложными анимациями) разработчики часто комбинируют React с библиотеками вроде RxJS, получая лучшее из двух миров.

Top comments (3)

Collapse
 
schekhovtsov profile image
Sergey Schekhovtsov

Отличная статья, написанная простым и понятным языком. Доходчиво, с примерами. Буду рекомендовать.

Collapse
 
tosha4encko profile image
tosha4encko

Сперва вы путаете реактивность с программированием потоков данных.
Далее вы путаете паттерны PubSub и Observable
А в конце вообще зачем-то лезете внутрь компонента, обосновывая принадлежность парадигме особенностями внутренней реализации.

По вашей логике, если в pipe`е RxJS есть bufferTime, то поток перестает быть реактивным? Ну дурость же

Collapse
 
daedalius profile image
Dmitriy Tishin

То есть когда React заботится о производительности и батчит апдейты UI в ответ на часто меняющееся состояние - он перестает быть реактивным?

Суть же в том, что он изменение состояния переводит в изменения на UI. State/context обновился - приложение перерисовалось - изменения отобразились. Сами.

количество и время появления событий не контролируются.

так никто и не контроллирует то как часто state/context меняются