Загляните в мой блог о том, как создавать веб-игры здесь.



RxJS, пожалуй, самая крутая библиотека для решения сложных, асинхронных и загадочных проблем в веб-разработке с легкостью и совершенство. Приложения RxJS достаточно разнообразны, чтобы классифицировать его как достаточно универсальную библиотеку. Учитывая то ограниченное время, которое я потратил на использование RxJS, я уже нашел несколько классических приложений RxJS в дикой природе.
Однако, если честно, для новичка , немного сложно удержаться, и вот почему.

Что такое RxJS?

Знание, что такое RxJS и как он помогает, является наиболее важной частью обучения. Давайте посмотрим на некоторые определения, полученные от Google.

RxJS - это библиотека для реактивного программирования с использованием Observables, чтобы упростить составление асинхронного кода или кода на основе обратного вызова.

Реактивное программирование - это просто другой способ создания программных приложений. По сути, ваше программное обеспечение создано для «реакции» на происходящие изменения, а не для типичного способа написания программного обеспечения, при котором мы явно пишем код (также известный как «императивное» программирование) для обработки этих изменений.

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

Все это звучит потрясающе, однако у нас до сих пор нет четкого представления о том, зачем нам вообще нужен RxJS.

Что на самом деле делает RxJS?

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

RxJS использует Observables для наблюдения (очевидно) за этими событиями и выполнения операций (операторов RxJS) для получения значимых результатов.

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

Теперь у всех событий в моем приложении будет соответствующий наблюдатель, который точно знает, как обрабатывать соответствующее событие. Мы перешли от традиционных к более реактивным отношениям между данными и представлением.

Почему мне должен быть интересен RxJS?

Асинхронный поток данных

В React обычно мы используем flux, Redux, Mobx, MST для обработки наш поток данных. Однако ни одна из этих библиотек не решает проблему асинхронности. В Redux у нас есть промежуточное ПО для обработки асинхронной логики, например Thunk.

Однако сам Thunk связан с некоторыми проблемами, такими как несоответствие хранимых данных и данных, отправленных на сервер. Кроме того, это усложняет наш редуктор из-за слишком большого количества переменных для реализации простой общей логики.

Вышеупомянутые проблемы подробно описаны в этих блогах.





RxJS имеет элегантный API для эффективной обработки всей асинхронной логики, который мы рассмотрим позже. Здесь также довольно легко реализовать обработку ошибок и отмену запроса.



Делайте больше с меньшим количеством кода

RxJS по своей природе представляет собой компактную библиотеку для реактивного программирования.
Довольно сложные функции могут быть легко реализованы с помощью Observables и Операторы .

Всегда есть оператор. Каким бы ни был вариант использования.

Идея никогда больше не писать сложную логику звучит привлекательно.

Новая функция с минимальным рефакторингом

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

Практический пример RxJS

Не секрет, что у RxJS довольно крутая кривая обучения, и его использование требует практики.
Теперь, похоже, самое подходящее время упомянуть, как легко сделать ошибку при использовании Observables. Если вы только начинаете с RxJS, скорее всего, вы делаете некоторые типичные ошибки, которые обычно допускают разработчики. Не волнуйтесь, в следующей статье все это объясняется.



Лучший способ изучить RxJS - использовать соответствующий пример. Представляем…

Реактивные войны

ReactiveWars - это простое одностраничное приложение React, которое использует RxJS для обработки потока данных. Мы будем использовать StarWars API для получения результатов поискового запроса от пользователя и отображения результатов.

Полный код оформления заказа здесь

Цель

Возьмем 3 типа сущностей, которые мы можем запросить из SWAPI.
1 ›Люди
2› Планеты
3 ›Транспорт
Позвоним эти параметры как Настройки, которые пользователь может выбрать или отменить.
Все три настройки доступны в виде кнопок в пользовательском интерфейсе для выбора и отмените выбор.
У нас также есть кнопка поиска для получения результатов и поле ввода.
Мы должны убедиться, что не выполняются избыточные вызовы.
Окончательный пользовательский интерфейс выглядит примерно так.

Давай поиграем

Теперь мы готовы углубиться в код.
Я создал стандартный проект create-response-app , добавил RxJS как зависимость и реализовал пользовательский интерфейс, показанный выше. Кнопки заполняются путем сопоставления массива состояний предпочтений, показанного ниже.

MakeCallStream

Давайте обработаем нажатия кнопки Поиск с помощью RxJS Темы.
Мы собираемся создать новый поток для кнопки поиска и отправлять события в этот поток при каждом нажатии кнопки.
Здесь мы используем flatMap из RxJS.

Нам нужно пройти через массив this.state.prefStatus и выполнить выбранные вызовы только для этих настроек.

Код: -

InputBoxStream

Давайте создадим inputStream, чтобы принять изменения в поле ввода и установить его в состояние.
Он сделал что-то вроде этого.

PrefButtonStream

Давайте рассмотрим наши требования здесь

1 ›Нам нужно выбрать / отменить выбор кнопки при нажатии.

2 ›Нам также необходимо выполнить вызовы API, чтобы обновить наш список в соответствии с выбранными настройками. (Наш makeCallStream выше уже позаботился об этом).

3 ›Если нажатая кнопка является единственной выбранной кнопкой, мы хотим пропустить это событие, потому что всегда должна быть выбрана хотя бы одна кнопка pref.

Теперь давайте реализуем это в RxJS

GetDataStream

Наши требования следующие

1 ›Нам нужно получать данные для каждого отдельного поискового запроса.

2 ›Мы должны следить за тем, чтобы не производились избыточные вызовы. Для этого мы используем оператор independentUntilChanged.

3 ›Нам нужно обрабатывать ошибки в вызове API. Мы используем catchError и передаем пустой Observable для обработки случая ошибки здесь.

4 ›Мы увидим, как передавать данные по нисходящему потоку для использования на более позднем этапе с помощью оператора of .

Это выглядит примерно так

И вот оно, мы выполнили все, что обещали. Вот как это выглядит.

Полный код оформления заказа для этого здесь.

Дополнительные функции / изменения

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

1 ›Допустим, мы хотим ограничить частоту одновременных вызовов, когда пользователь выбрал несколько настроек и выполнил поиск. Поэтому нам нужно обеспечить, чтобы все вызовы происходили только с интервалом 500 мс.

Этого можно добиться с помощью простого рефакторинга, описанного ниже в getDataStream, с использованием оператора debounceTime.

getDataStream.pipe(
debounceTime(500), // debounce concurrent calls by 500ms
flatMap(val => {
return fetch(`https://swapi.co/')
}),
...

2 ›Предположим, мы хотим выполнять вызовы API при каждом изменении текста, но опять же, мы не должны делать никаких избыточных вызовов.

Это снова достижимо с помощью простого рефакторинга в inputStream, где мы вызываем makeCallStream.

inputStream.subscribe(val => {
  this.setState({
     searchText: val.value
   }, () => makeCallStream.next({ value: this.state.searchText });
});

3 ›Наконец, предположим, что нам нужно объединить несколько вызовов в цепочку. Например, когда пользователь нажимает на элемент люди, мы должны выбрать его автомобиль, а затем распечатать старшего из пилотов (людей), которые когда-либо использовали этот автомобиль.

Мы можем связать эти запросы и использовать flatMap для достижения окончательного результата.

vehicleDeepStream.pipe(
flatMap(person => fetch('vehicle/of/person')),
flatMap(vehicle => fetch('all/pilots/of/vehicle')),
flatMap(allPilots => eldest(allPilots)),
).subscribe(eldest => console.log(eldest))

А что, если бы мы хотели ограничить API человека на 100 мс, а API транспортного средства - на 200 мс?

Опять же, это требует простого рефакторинга.

vehicleDeepStream.pipe(
debounceTime(100),
flatMap(person => fetch('vehicle/of/person')),
debounceTime(200),
flatMap(vehicle => fetch('all/pilots/vehicle')),
flatMap(allPilots => eldest(allPilots)),
).subscribe(eldest => console.log(eldest))

Заключение

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

Некоторые крупные компании, использующие RxJS, включают

Microsoft,
Netflix,
GitHub,
SoundCloud,
Trello,
Treehouse,
Slack and more

Узнать больше здесь.
Надеюсь, это поможет вам начать работу с RxJS для React.
Ознакомьтесь с моим redux-observable пример приложения для ReactNative.