Wprowadzenie do RxJS

Co to jest RxJS?

Jest to biblioteka, która ułatwia korzystanie ze zdarzeń asynchronicznych. Takie zdarzenia znajdziemy w każdym rodzaju aplikacji. Piszą aplikacje webowe znajdziemy między innymi:

  • Zdarzenia http - POST, PUT, GET, DELETE
  • Mouse events
  • Timeout, interval
  • Wylogowanie, zalogowanie
  • Zmiana w bazie danych

Tworzenie, przekształcanie i przechwytywanie odbywa się za pomocą strumieni. Każdy strumień posiada zestaw danych, który może się zmieniać.

Możemy sobie to zobrazować na przykładzie strumienia autoryzacji. Załóżmy, że będą nas interesowały dwa stany (zalogowany i niezalogowany).

Dla stanu niezalogowanego przyjmijmy zestaw danych null. Czyli nie posiadamy żadnych danych.

Natomiast dla stanu zalogowanego będzie klasa Auth. W niej będzie możliwe przechowywanie danych odpowiadających konkretnemu użytkownikowi.

Podsumowując, posiadamy strumień, który na konkretne zdarzenia zwraca nam null lub klasę Auth.

Observable, Subscription i Subject niezbędne elementy w RxJS

Zrozumienie w pełni jak działa RxJS wiąże się z poznaniem podstawowych pojęć. Musimy poznać jak działają strumienie. Dlatego na początek poznamy klasę odpowiedzialną za strumień. Klasę, która wyciąga dane ze strumienia i klasę, która tworzy i przekazuje dane do strumienia.

  1. Observable
  2. Subscription
  3. Subject

Observable

Jest to klasa, która reprezentuje strumień. W niej przechowujemy dane i ona zwraca nam aktualny stan (zestaw danych). Przyjęło się, że obiekt Observable w nazwie zmiennej kończy się znakiem $. Jest to ogólna zasada przyjęta przez programistów.

auth$: Observable<Auth>;

Subscription

Nasłuchiwanie danych ze strumienia odbywa się za pomocą funkcji subscribe udostępnioną przez Observable. Funkcja zwraca nam klasę Subscription.

const sub = auth$.subscribe((auth: Auth) => {
  console.log(auth);
});

W przykładzie powyżej przypisałem nasłuchiwanie zmian do zmiennej sub. Nie jest to konieczne możemy nasłuchiwać zmiany bez przypisywania do zmiennych. Problem zaczyna się, gdy będziemy chcieli przestać nasłuchiwać. Dlatego w takim przypadku, jedna z możliwości jest funkcja unsubscribe() w klasie Subscription.

sub.unsubscribe();

Subject

Przyszła pora na stworzenie i przekazanie danych do strumienia. Możemy uzyskać to za pomocą klasy Subject. Tworzy się ją bardzo prosto

const subject = new Subject();

Możemy do tej klasy przekazać dane, które przy subskrybowanie klasy Observable będą zwracane. W takim przypadku używamy funkcji next(). Dla naszego przykładu ze strumieniem autoryzacji możemy przekazać albo null, albo klasę Auth.

subject.next(null);
subject.next(new Auth());

Gdyby zaszła potrzeba przekazania error to korzystamy z funkcji error().

subject.error(new Error('some error'));

Natomiast możemy w każdym momencie zakończyć strumień. Działa to tak samo, jak funkcja unsubscribe() opisana wcześniej.

subject.complete();

Aby klasę Subject przekształcić w klasę Observable, skorzystamy z funkcji asObservable().

const obs$ = subject.asObservable();

Posiadamy parę rodzai tej klasy, różnią się one sposobem przekazywania i odbierania danych:

  • Subject
  • BehaviorSubject
  • ReplaySubject
  • AsyncSubject

Observable dla autoryzacji

Podsumowując posiadamy już niezbędną wiedzę do stworzenia, przekazania i odbierania informacji ze strumieni. Więc zatem zbierzmy to w całość i napiszmy strumień do autoryzacji.

authSubject = new Subject();
auth$ = authSubject.asObservable();

auth$.subscribe(auth => {
    console.log(auth);
})

auth.next(null);
auth.next(new Auth());

Operatory, przekształcanie strumieni

RxJS udostępnia szereg operatorów, dzięki którym możemy przekształcać strumienie. Aby dodać jakiś operator, należy skorzystać z funkcji pipe() dla Observable. Jak kolejne argumenty dodajemy kolejno operatory.

const observable: Observable<number>;

observable
    .pipe(
        map((nr: number) => `Current number is ${nr}`)
    )
    .subscription((nr: string) => {
        console.log(nr);
    })

Możemy skorzystać z przeróżnych operatorów. Listę dostępnych znajdziecie tutaj. W naszym przykładzie skorzystamy z dwóch podstawowych operatorów (map i filter).

Map

Wróćmy do naszego przykładu ze strumieniem autoryzacji.

Skorzystamy z podstawowego operatora, jakim jest map. Działa on bardzo podobnie jak map dla Array. Tworzy nowy, przekształcony zestaw danych z istniejącego.

Załóżmy, że chcemy posiadać strumień zwracający nam informacje boolean czy jesteśmy zalogowani czy nie.

Przekształćmy więc dane typu null i Auth na dane typu boolean.

auth$
    .pipe(map(x => !!x))
    .subscribe((isLogged: boolean) => {
      console.log(isLogged);
    });

Filter

Jeśli będziemy chcieli wykonać jakąś akcje tylko dla stanu zalogowanego będziemy musieli przefiltrować dane.

Posłużymy się operatorem filter.

Dzięki niemu funkcja w Subscription wykona nam się tylko dla stanu zalogowanego.

auth$
    .pipe(
      map(x => !!x),
      filter(x => !x)
    )
    .subscribe((logged: boolean) => {
      console.log(logged);
    });

Podsumowanie

Przedstawiłem uogólniony przykład użycia RxJS.

Nie dodałem wyłapywania błędów ani zakończania strumieni.

Podsumowując, RxJS przyśpiesza tworzenie aplikacji i jej późniejsze rozwijanie. Kod staje się bardziej czytelny.

Copyright © 2021 DevLuk