Angular Route Resolves in 10 Minutes

Updated on 07/13/2018: Rozległy remont kodu, aby użyć nowszych konwencji. Zaktualizowano Angular i RxJS do najnowszych dostępnych wersji, przeniesiono przykłady do StackBlitz.

Celem tego postu jest zademonstrowanie, jak Angular route resolves działają w 10 minut, wraz z dostarczeniem przykładowego kodu na Stackblitz. Jeśli jesteś już zaznajomiony z route resolves z AngularJS, polecam pominąć intro i przeskoczyć prosto do sekcji z przykładową aplikacją.

Table of Contents

Intro
Sample App

  • Krok 1: Utwórz klasę Resolver
  • Krok 2: Dodaj strażnika Resolve do trasy
  • Krok 3: Pobierz rozwiązane dane z aktywowanej trasy komponentu

Wskazówki &Porady

  • Avoiding Redundant API Calls
  • Multiple Resolves on the Same Route
  • Passing Route Params to the Resolver

Uwagi końcowe

Intro

Route resolves to nic innego jak sposób na wstępne pobranie danych, których komponent potrzebuje przedpobierania danych, których potrzebuje komponent przed jego inicjalizacją. Zazwyczaj dane te pochodzą z API. Załóżmy, że masz komponent, którego jedyną rolą jest wyświetlanie wykresu dziennej sprzedaży w danym miesiącu; Nie ma sensu renderować widoku lub ładować tego komponentu, zanim dane o sprzedaży nie będą dostępne. W rzeczywistości, wiele bibliotek wykresów wyrzuci błąd, jeśli spróbujesz zainicjalizować wykres przed dostarczeniem mu danych (i tak samo będzie w przypadku *ngFor). Oczywiście możesz łatwo obejść ten problem, ukrywając html za pomocą *ngIf lub tymczasowo dostarczając pustą tablicę, dopóki nie zostaną załadowane niezbędne dane. Jednakże, podczas gdy można obejść się bez resolve, ich implementacja pomaga uczynić kod bardziej czytelnym i łatwym w utrzymaniu poprzez:

  1. Eliminację mylącego bałaganu w szablonie i kodzie komponentu.
  2. Wyjaśnienie intencji przez pokazanie, które dane muszą być wstępnie pobrane.

Mimo tych korzyści, wiele stron unika używania resolwerów na rzecz wyświetlania większości komponentu i pokazywania spinnera w sekcjach, dla których dane są wciąż ładowane. W niektórych przypadkach, takie podejście jest pożądane z punktu widzenia UX, a resolve nie powinno być używane. Użyj swojego uznania.

Sample App

Open Sample App

Jak widać, naszym punktem wyjścia jest bardzo podstawowa aplikacja z dwoma ścieżkami – „Home” i „News”. Nawigacja pomiędzy trasami odbywa się poprzez kliknięcie na odpowiednią zakładkę. Zamierzamy dodać resolve, które będzie pobierało wiadomości z API zanim załaduje się komponent News. W tym celu wykonamy trzy kroki:

Krok 1: Utworzenie klasy resolver, która wykona wywołanie Http w celu wstępnego pobrania danych, których potrzebujemy.

Utwórz nowy plik Typescript wewnątrz folderu app i nadaj mu nazwę:

news-resolver.service.ts

Następnie skopiuj i wklej następujący kod do swojego nowego pliku (wyjaśniony poniżej):

Rozbijmy to, co zrobiliśmy w powyższym kodzie:

  • Dodaliśmy deklaracje importu ES6, aby wprowadzić niezbędne moduły.

  • Utworzyliśmy nową klasę TypeScript NewsResolver.

  • Dodaliśmy interfejs Resolve do naszej klasy – jest to OPCJONALNE, ale każda klasa, którą planujemy wykorzystać jako resolver musi implementować metodę resolve, więc jest to dobra konwencja.

  • Dodaliśmy metodę resolve() do NewsResolver – jest to metoda odpowiedzialna za zwracanie danych, które są nam potrzebne. Nazwanie metody, która zwraca dane dla resolve guard „resolve” NIE jest opcjonalne – resolver nie zadziała, jeśli metoda zostanie nazwana inaczej.

  • Jeśli zauważyłeś, że w powyższym kodzie błędnie użyto żądania POST zamiast GET, masz całkowitą rację; W prawdziwej aplikacji byłoby to żądanie GET. Przykłady tutaj wykorzystują , który jest stroną udostępniającą testowe punkty końcowe API.

Przed przejściem dalej, musimy włączyć klasę resolvera, którą właśnie stworzyliśmy do naszego modułu routingu. Przejdź do app-routing.module.ts i dodaj NewsResolver do tablicy providers. Lub, jeśli dopiero zaczynasz pracę z Angularem 2, po prostu zastąp zawartość app-routing.module.ts poniższym kodem – zmiany oznaczone są notatkami:

W ten sposób mamy już zdefiniowaną klasę resolvera. W kolejnych krokach dodamy ją do naszej trasy.

Kod po dodaniu klasy resolvera

Krok 2: Dodaj strażnika resolve do trasy.

W app-routing.module.ts zmień następującą linię kodu { path: 'news', component: NewsComponent } na:

{ path: 'news', component: NewsComponent, resolve: { news: NewsResolver }}

Wszystko, co tutaj zrobiliśmy, to dodanie strażnika resolve, który właśnie zdefiniowaliśmy do naszej trasy news. To mówi Angularowi, że musimy poczekać, aż metoda NewsResolver’s resolve() zwróci dane, zanim wyświetlimy NewsComponent.

Ważne jest, aby zaznaczyć, że news w linii news: NewsResolver kodu jest tym, co wybrałem, aby nazwać jakiekolwiek dane zwracane przez resolver. Możesz nazwać go jakkolwiek chcesz.

Jako trochę styczna uwaga – jeśli nie jesteś zaznajomiony z Angular route guards w ogóle, i chciałbyś wiedzieć więcej, dokumentacja jest tutaj. Zagłębianie się w szczegóły na temat straży jest poza zakresem tego postu, ale powinieneś wiedzieć, że istnieją inne straże poza resolve, które są dostępne, dlatego właśnie przywołałem ten termin.

Kod z dodaną strażą Resolve

Krok 3: Pobierz rozwiązane dane z aktywnej trasy komponentu.

Teraz, gdy mamy klasę resolvera i dodaliśmy ją do naszej trasy, dane są wstępnie pobierane. Ostatnim krokiem jest dostęp do wstępnie pobranych danych w naszym NewsComponent znajdującym się w app/news.component.ts. Przejdź do tego pliku i dodaj następujący moduł ES6:

import { ActivatedRoute } from '@angular/router';

następnie udostępnij ActivatedRoute w konstruktorze komponentu News poprzez dodanie następującego kodu na górze definicji klasy NewsComponent:

constructor(private route: ActivatedRoute) {}

Jak już wiesz, lub mogłeś się domyślić, ActivatedRoute pozwala nam na dostęp do informacji o trasie, która jest aktualnie aktywna, takich jak adres url trasy, parametry zapytania, itp. To co nas tutaj interesuje to dane o aktualnościach, które są ładowane do ActivatedRoute z resolve guard. Aby pobrać dane wiadomości z trasy, dodaj właściwość przechowującą dane wiadomości:

public news: any;

, a następnie pobierz dane z aktywnej trasy, gdy NewsComponent zostanie zainicjalizowany:

 ngOnInit(): void { this.news = this.route.snapshot.data; }

To praktycznie wszystko. Zmień szablon komponentu wiadomości, aby wyświetlał wiadomości z rozwiązanej trasy, usuwając obecną zawartość:

<div>This is just a placeholder for now. News will go here. </div>

i zastępując ją:

Teraz powinieneś zostać przywitany najnowszą wiadomością, „Niebo jest niebieskie”, po kliknięciu zakładki Wiadomości.

Dokończony kod

Wskazówki &Porady

– Rezolucje mogą powodować nadmiarowe wywołania API: Resolve pobiera dane za każdym razem, gdy komponent jest ładowany. Często powoduje to niepotrzebne wywołania API, które negatywnie wpływają na wydajność. Jeśli resolve pobiera dane, które nie zmieniają się często, rozważ zapisanie danych zwracanych przez resolve do właściwości w klasie resolvera i po prostu zwrócenie tej właściwości, jeśli została już ustawiona. Na przykład, w naszym przykładzie, dodalibyśmy początkowo niezdefiniowaną właściwość news w taki sposób: public news: any = undefined; w naszym resolverze newsów. Następnie, w metodzie resolve(), sprawdzimy czy właściwość news jest już ustawiona i zwrócimy jej wartość bez wywoływania API, jeśli tak, czyli:

 resolve(): Observable<any> { if (this.news) { return this.getSavedNews(); } else { return this.getNewsFromApi() } }

Pełny przykład kodu poniżej. Jeśli składnia obserwowalna wydaje ci się nieco niezwykła, to dlatego, że używam RxJS 6. Istnieje dobry tutorial na temat zmian wprowadzonych ostatnio do RxJS tutaj, jeśli potrzebujesz odświeżenia.

Return Saved Data, if Already Fetched from API

Naturalnie, możesz pójść dalej i ustawić okres czasu, w którym dane są ważne, nie tylko zapisując dane, ale dodając kolejną właściwość timestamp i wykonując wywołanie API, jeśli dane są starsze niż x.

– Podobnie jak w AngularJS, możesz użyć wielu resolve na tej samej trasie. Wywołania resolve są wykonywane równolegle, a komponent zostanie załadowany dopiero wtedy, gdy wszystkie wywołania zwrócą dane. Aby użyć wielu resolwerów, po prostu dodaj je do trasy:

Wtedy dodatkowe dane resolwera mogą być dostępne z migawki trasy tak jak pojedynczy resolwer:

 ngOnInit(): void { this.news = this.route.snapshot.data; this.alternativeNews = this.route.snapshot.data; }

Kod z wieloma resolwerami

– resolwer ma dostęp do parametrów trasy. Załóżmy, że masz komponent, który wyświetla listę tytułów wiadomości. Po kliknięciu na artykuł, otwierany jest inny komponent, który wyświetla pełny artykuł. Przed załadowaniem tego komponentu, musimy wstępnie pobrać zawartość newsa, którego tytuł został kliknięty – można to zrobić w metodzie resolve. Klasa resolver ma dostęp do ActivatedRoute, więc możemy uzyskać id historii, która została kliknięta:

 resolve(route: ActivatedRouteSnapshot) { let id: any = route.params); return this.getNewsStory(id); }

Jest to dość oczywiste. Dla przykładu, sprawdź nowy plik src/news-story-resolver.service.ts w linku poniżej. Odnośniki do nowego komponentu zostały dodane w zakładce News (news.component.ts).

Code With Parameterized Resolve

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.