Наивная бесконечная прокрутка в реактивном программировании с использованием наблюдаемых RxJS
Простой эксперимент по реализации бесконечной прокрутки с помощью RxJS
Сообщение в блоге о реализации Angular: Директива Simple Infinite Scroller с помощью RxJS Observables
Что такое реактивное программирование?
Проще говоря, это программирование с использованием асинхронных потоков данных. Есть отличный пост от Andre Staltz - Введение в реактивное программирование, которого вам не хватало, в сопровождении видео на egghead.io.
Введение в реактивное программирование, которого вам не хватало
Https://egghead.io/courses/introduction-to-reactive-programming
Что такое RxJS?
RxJS или Reactive Extensions - это библиотека, разработанная Microsoft Open Technologies на Javascript для преобразования, составления и запросов потоков данных. Https://github.com/Reactive-Extensions/RxJS
Бен Леш сделал отличный доклад на тему Реактивное мышление с RxJS 5.
Ниже приведены несколько хороших знакомств с Observables и несколько операторов от Netanel Basal.
Что мы будем строить?
Мы собираемся построить наивный бесконечный скроллер, используя наблюдаемые. Всякий раз, когда пользователь прокручивает данный контейнер до 70%, мы запускаем вызов api для получения дополнительных данных с сервера. Для этой реализации мы будем использовать неофициальный api HackerNews, чтобы получать последние новости.
Ниже приведены операторы, которые мы будем использовать из RxJS.
map
: аналогично отображению в массиве, отображение потока входящих данных.filter
: аналогично фильтру в массиве, фильтрует поток входящих данных.pairwise
: возвращает массив текущих переданных данных, а также ранее переданных данных.startWith
: возвращает наблюдаемое, испускает предоставленные значения перед тем, как испускать значения из наблюдаемого источникаexhaustMap
: ожидает передачи значения, пока не завершится переданный внутренний наблюдаемый объект
Ссылка на вывод в jsbin.com: https://output.jsbin.com/punibux
# Phase1 - настройка базового HTML и стилей.
Импортируйте библиотеку RxJS, и мы будем использовать infinite-scroller
в качестве контейнера прокрутки и добавлять к нему новости.
# Phase2 - настройка вспомогательных функций для обработки данных, рендеринга и вычислений.
Первые три функции просты,
getQuotesAPI
- возвращает URL-адрес API с номером текущей страницы в качестве параметра запросаprocessData
- обрабатывает возвращаемые данные из api, что выполняется с помощью fetch API и увеличивает currentPage.renderNews
- берет каждую новость и отображает ее в представлении.
Следующие две функции используются для вычислений прокрутки.
4. isUserScrollingDown
- определяет, прокручивает пользователь вниз или нет.
5. isScrollExpectedPercent
- определяет, прокрутил ли пользователь до переданного процента, чтобы получить больше данных.
# Phase3 - настройка наблюдаемого потока
Чтобы фиксировать события прокрутки в контейнере, нам нужно создать наблюдаемый из события прокрутки. Этого можно добиться с помощью Rx.Observable.fromEvent
- docs. Это соглашение о добавлении $
к переменной при обращении к наблюдаемому потоку.
# Phase4 - логика потока для обработки событий прокрутки и вызова API
Мы собираемся взять событие прокрутки, генерируемое scrollEvent$
и map
, чтобы принять только те значения, которые нам нужны для нашей логики бесконечной прокрутки. Нам нужно всего три свойства из элемента scroll - scrollHeight
, scrollTop
и clientHeight
.
Мы передаем сопоставленные данные оператору pairwise
, который генерирует текущее и предыдущее значение в массиве, который будет выглядеть, как показано ниже.
Теперь мы можем взять пару позиций и передать ее filter
им для фильтрации в соответствии с нашими условиями.
- Прокручивает ли пользователь вниз
- Достигнуто ли прокруткой пользователя семьдесят процентов контейнера
requestOnScroll$
- вызывается, когда userScrollDown$
проходит условия фильтрации. Начнем с начального значения пустого массива.
Мы собираемся использовать Rx.Observable.fromPromise
для создания наблюдаемого из обещания. fetch
выполняет HTTP-вызов и возвращает обещание. exhaustMap
будет ждать завершения выборки, а внутренний наблюдаемый объект выдаст данные из API.
Observables ленивы - это означает, что они ничего не делают, пока вы на них не подпишетесь. Мы подпишемся на requestOnScroll$
и передадим processData
методу подписки. Когда exhaustMap
передает данные из API, они передаются processData
, который вызывает renderNews
для рендеринга в представлении.
Ниже показано изображение бесконечной прокрутки в действии, обратите внимание на полосу прокрутки справа.
В своем следующем посте я попытаюсь реализовать это в Angular 2, создав директиву бесконечной прокрутки.
Обновление: вот ссылка на мой последующий пост о Директиве Simple Infinite Scroller с RxJS Observables