[Перевод] Обмен данными между React-компонентами с использованием библиотеки RxJS

Перед вами перевод статьи Chidume Nnamdi, опубликованной на blog.bitsrc.io. Перевод публикуется с разрешения автора.

snbfh_weeuiwnpbdta7qdkpjxes.jpeg

Появление библиотеки RxJS открыло массу новых возможностей в мире JS. Цель RxJS — достигать многого, используя небольшое количество кода. Прочитав эту статью, вы узнаете, как осуществлять обмен данными между компонентами приложения на React, применяя возможности RxJS.

Совет: используйте Bit для организации React-компонентов и обмена ими. Это позволит вашей команде быстрее разрабатывать свои приложения. Просто попробуйте.

dh0wpix46rdg6rkxrqwi7e0qels.gif
React Components Collection

Redux


Обмен данными между несвязанными React-компонентами — это то, ради чего были созданы библиотеки управления состояниями. Существует множество шаблонов для управления состояниями, но наиболее известны два: Flux и Redux.

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

Работая с Redux, первым делом мы создаем централизованное хранилище данных:

nwmaim9uwgixbjr64pi-3oteoyw.png

Далее связываем компоненты с этим хранилищем и при желании обновляем или удаляем состояние. Любые изменения, внесенные в хранилище, будут отражены в компонентах, связанных с ним. Таким образом, поток данных распространяется на все компоненты, независимо от степени их вложенности. Компонент, находящийся на энном уровне иерархической структуры, способен передавать данные компоненту самого высокого уровня. Последний, в свою очередь, может передавать данные компоненту 21 уровня.

RxJS


С появлением RxJS использовать библиотеки управления состояниями стало гораздо проще. Многим понравился паттерн «Наблюдатель» (Observer), предоставляемый RxJS.

Мы просто создаем поток Observable и даем возможность всем компонентам прослушивать его. Если какой-то компонент добавляется к потоку, прослушивающие (или «подписанные») компоненты реагируют на обновление DOM.

Установка


Создаем приложение на React, используя create-react-app. Если у вас нет create-react-app, то сперва установите его глобально:

npm i create-react-app -g


Далее генерируем проект в React:

create-react-app react-prj


Переходим в директорию:

cd react-prj


Устанавливаем библиотеку rxjs:

npm i rxjs


У нас должен появиться файл, создающий новый экземпляр BehaviourSubject.

Почему мы используем BehaviorSubject?


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

Таким образом, BehaviorSubject:

  • Позволяет осуществлять массовую рассылку.
  • Хранит последние значения, опубликованные подписчиками, и делает массовую рассылку этих значений.


dabv2q9qj8_aw8ng2ae6souzlki.png

В папке src находится файл messageService.js, экспортирующий подписчику экземпляр BehaviorSubject и объект messageService. Объект-подписчик создается в начале файла — так он доступен для любого импортирующего компонента. У объекта messageService имеется функция отправки, принимающая параметр msg: в нем содержатся данные, которые нужны для передачи всем прослушивающим компонентам. В теле функции мы вызываем метод emit. Он осуществляет массовую рассылку данных подписанным компонентам в объекте-подписчике.

Предположим, что у нас есть следующие компоненты:

  • ConsumerA;
  • ConsumerB;
  • ProducerA;
  • ProducerB.


В иерархической структуре они выглядят так:

xfa5ze9qtqtjnuqevc-qiz5i5ng.png

Компонент приложения передает сообщение ProducerA и ConsumerB. ProducerA отправляет данные ConsumerA, а сообщение от ConsumerB попадает к ProducerB.

86kyqhhdskohzsnh_t_ec6ryq4s.png

Компоненты ConsumerA и ConsumerB имеют индивидуальный счетчик состояния. В их методе componentDidMount они подписаны на один и тот же поток subscriber. Как только публикуется какое-либо событие, у обоих компонентов обновляется счетчик.

У ProducerA и ProducerB есть кнопки Increment Counter и Decrement Counter, которые при нажатии выдают 1 или -1. Подписанные компоненты ConsumerA и ConsumerB подхватывают событие и запускают свои функции обратного вызова, обновляя значение счетчика состояния и DOM.

eii2zufqf2-ddtuyzpl-rqzd2qi.gif

Посмотрим на иерархическую структуру еще раз:

prv4hsqntkcolmmgz1bsnxmdyuc.png

ProducerB передает данные ConsumerA, хотя они абсолютно не связаны. ProducerA передает данные ConsumerB, не являясь его родительским компонентом. В этом вся суть RxJS: мы просто создали центральный узел потока событий и позволили компонентам прослушивать его. Когда какой-либо компонент генерирует события, прослушивающие компоненты тут же подхватывают их.

Поиграть с приложением можно на stackblitz: https://react-lwzp6e.stackblitz.io

Заключение


Итак, мы увидели, как можно осуществлять обмен данными между React-компонентами, применяя RxJS. Мы использовали BehaviourSubject для создания централизованного потока данных, а затем позволили остальным компонентам подписаться на этот поток. Теперь, когда один из компонентов генерирует данные, прочие компоненты также получают их. Уровень компонентов в иерархической структуре неважен.

Если у вас есть вопросы относительно этой темы или вы хотите, чтобы я что-то добавил, исправил или удалил, напишите об этом в комментариях, в электронном письме или в личном сообщении.

Спасибо за внимание!

© Habrahabr.ru