Wróć do strony głównej
Angular

Między nami dyrektywami – Directive Composition API

W tym artykule dowiesz się, czym jest </span><span style="font-weight: 400;">Directive composition API, dlaczego jego wypuszczenie na świat trwało tak długo, jakie rozwiązuje problemy oraz jakie są jego zalety i wady. 

Czym więc jest </span>Directive composition API? Jest to funkcjonalność, która umożliwia łączenie dyrektyw z innymi dyrektywami i… to by było na tyle! Wydaje się proste, prawda? Moglibyśmy rozmyślać, czy ta funkcjonalność nie powinna być dostępna już we wcześniejszych wersji Angulara? To pytanie pojawia się już od jakiegoś czasu, a dokładniej od 23 maja 2016 roku, kiedy to powstała pierwsza wzmianka na github na ten temat, a data ta zbiega się z publikacją pierwszego release’a Angular 2, która miała miejsce w maju 2016 roku.

Dlaczego trwało to tak długo?

Temat był bardzo popularny wśród społeczności angularowej, a prawie 1,5 roku po stworzeniu issue pojawiło się światełko w tunelu. Twórca angulara zapowiedział, że po wprowadzeniu kompilatora Ivy będzie to wykonalne.

Po wprowadzeniu Ivy w Angular 8, społeczność odświeżyła wątek i ponownie poprosiła o informacje na temat przyszłych planów dotyczących tej funkcjonalności, a kilka miesięcy później otrzymali je – realizacja takiej funkcji wymagałaby poważnej refaktoryzacji ze względu na niekompatybilne struktury danych. W końcu, 13 listopada 2020 roku, </span><span style="font-weight: 400;">Directive composition API została dodana do oficjalnej roadmapy. Wraz z 15 wersją Angulara ta długo oczekiwana funkcjonalność została wreszcie wprowadzona.

Jakie problemy rozwiązuje Directive composition? 

Spójrzmy na poniższy przypadek użycia. Wyobraźmy sobie, że mamy trzy komponenty

GIF

współdzielą one pewną funkcjonalność – zmiana kolorów (wszystkich z nich), ustawienie stanu </span><span style="font-weight: 400;">disabled (button i toggle). Najprostszym sposobem na osiągnięcie tego jest wykorzystanie </span><span style="font-weight: 400;">Inputów dla każdego z komponentów.

Takie podejście narusza zasadę DRY, więc zastanówmy się nad innym podejściem.

Jednym z możliwych rozwiązań jest wykorzystanie dziedziczenia. Możemy utworzyć komponent bazowy </span><span style="font-weight: 400;">BaseComponent, który będzie rozszerzał każdy następny komponent.

W takim przypadku komponent spinner będzie obsługiwał stan disabled, co jest niewłaściwe i ogólnie rzecz biorąc nie jest to najlepsza praktyka, by udostępniać API, które nie będzie wykorzystywane.

Aby to wyeliminować, możemy utworzyć dwie dyrektywy – dyrektywę Disable i dyrektywę Color. W ten sposób nasz kod będzie podzielony dla każdej funkcjonalności.

Z założenia, dyrektywy te zawsze będą używane w zakresie tych komponentów. Wyobraź sobie, że istnieje wiele instancji komponentów toggle: 

Występuje tutaj dosyć spora redundancja dyrektyw appColor oraz appDisable, co nie jest zbyt czytelne. W tym przypadku z pomocą przychodzi Directive composition API.

Od 15 wersji Angulara dostępne jest nowe property komponentu o nazwie hostDirectives. Pozwala ona określić tablicę dyrektyw, które powinny zostać zaaplikowane w naszych komponentach. Można również ustawić aliasy dla </span><span style="font-weight: 400;">Inputów i </span><span style="font-weight: 400;">Outputów, aby zapobiec konfliktom między dyrektywą a elementami hosta. Ważne jest, aby pamiętać, że dyrektywa używająca hostDirectives musi być standalone.  

Przyjrzyjmy się teraz naszym komponentom </span><span style="font-weight: 400;">toggle

Teraz jest to dużo czytelniejsze! 

W naszym przypadku skomponowaliśmy dyrektywy z komponentami, ale możliwe jest również komponowanie dyrektyw z innymi dyrektywami. 

Tutaj mamy dyrektywę ToggleThemeDirective, która składa się z ColorDirective, DisableDirective oraz posiada również swój własny skrawek funkcjonalności – zmianę kształtu toggle’a. Teraz musimy tylko zaaplikować naszą dyrektywę ToggleThemeDirective w następujący sposób: 

Kolejność wykonywania dyrektyw

Host Directives mają taki sam cykl życia jak inne komponenty i dyrektywy w templatce. Ważne jest, aby pamiętać, że wywołanie konstruktora, lifecycle hooków i bindingów dyrektyw hosta zawsze występują przed dyrektywą lub komponentem, do którego się odnoszą. 

Przeanalizujmy kolejność wykonywania ToggleComponent aplikującego ToggleThemeDirective. Dyrektywa ta, jak pokazano wcześniej, składa się z dyrektyw Disable, Color wraz z dodatkową funkcjonalnością. Załóżmy, że dyrektywy te mają zaimplementowany jedynie lifecycle hook ngOnInit.

Kolejność wykonywania wyglądałaby następująco: 

  1. Wywołanie konstruktora DisableDirective
  2. Wywołanie konstruktora ColorDirective
  3. Wywołanie konstruktora ToggleThemeDirective
  4. Dyrektywa Disable ngOnInit
  5. Dyrektywa Color ngOnInit
  6. Dyrektywa ToggleTheme ngOnInit
  7. Zaaplikowanie bindingów DisableDirective
  8. Zaaplikowanie bindingów ColorDirective
  9. Zaaplikowanie bindingów ToggleThemeDirective

Wydajność

Owa funkcjonalność jest naprawdę wygodna, chociaż czasami, gdy jest używana w nieprzemyślany sposób, może prowadzić do problemów związanych z alokacją pamięci. Dla przykładu, przyjrzyjmy się komponentowi </span><span style="font-weight: 400;">Toggle. Składa się on z dwóch dyrektyw i po wyrenderowaniu utworzone zostaną 3 obiekty (w tym obiekt toggle). Dla niewielkiej ilości komponentów toggle nie będzie to miało większego znaczenia, ale wyobraźmy sobie, że mamy ich setki (np. wewnątrz dużej tabeli), wtedy różnica może być zauważalna. 

Podsumowanie

Directive composition API</span><span style="font-weight: 400;"> to potężna, długo oczekiwana funkcjonalność, którą można wykorzystać do poprawy jakości i czytelności kodu. Trzeba jednak pamiętać, że korzystanie z niej powinno być świadomą decyzją ze względu na możliwe problemy z wydajnością, gdy jest używana w nieodpowiedniej sytuacji.

Dzięki za uwagę! 

 

O autorze

Łukasz Myszkowski

Angular Developer w House of Angular. Software Developer zgłębiający Angulara od początku swojej kariery. Przyszły właściciel Shiby Inu.

Zapisz się do naszego newslettera. Bądź na bieżąco z najnowszymi trendami, poradami, meetupami i stań się częścią społeczności Angulara w Polsce. Rynek pracy docenia członków społeczności.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *