Wróć do strony głównej
Angular

Przełom w Zarządzaniu Stanem – Odkryj Prostotę Signal Store, Część 1

Wstęp

Społeczność Angulara jest świadkiem dalszej transformacji, tym wskutek pojawienia się @ngrx/signals, narzędzia, które oznacza ważny krok w kierunku funkcjonalnego podejścia do zarządzania stanem. Ten przełom jest zgodny z ewoluującymi możliwościami Angulara, w szczególności z jego nowymi elementami podstawowymi: sygnałami. @ngrx/signals to nie tylko zarządzanie stanem; chodzi o przedefiniowanie sposobu zarządzania. Na pierwszy plan @ngrx/signals wysuwa prostotę, elastyczność i nową perspektywę funkcjonalną, dzięki czemu stanowi przełom dla programistów poszukujących wydajnych rozwiązań do zarządzania stanem.

Kontekst historyczny i ewolucja zarządzania stanem w Angularze

Podróż zarządzania stanem w Angularze została oznaczona przez różne podejścia i rozwiązania. Początkowo, deweloperzy Angulara zarządzali stanem za pomocą serwisów i RxJS, co było skuteczną metodą, ale często prowadziło do skomplikowanego, nieprzewidywalnego przepływu danych i braku określonej struktury, co jest trudne do debugowania. Pojawienie się NgRx wprowadziło bardziej uporządkowany sposób zarządzania stanem oparty na wzorcu Redux, poprawiając przewidywalność stanu, choć zwiększając boilerplate.

W miarę ewolucji Angulara i podejścia związanego z zarządzaniem stanem, biblioteki takie jak Akita i NGXS zaoferowały różne filozofie zarządzania stanem, koncentrując się na uproszczeniu doświadczenia dewelopera. Innym godnym uwagi rozwiązaniem był @ngrx/component-store, samodzielna biblioteka zapewniająca bardziej lekkie, reaktywne rozwiązanie.

Wprowadzenie @ngrx/signals oznacza najnowszą ewolucję na tej trajektorii. Łączy ono solidną architekturę NgRx z funkcjonalnym podejściem. Korzystając z podstawowych prymitywów Angulara, @ngrx/signals dostarcza elastyczny i efektywny sposób na zarządzanie stanem, efektywnie redukując boilerplate związany z tradycyjnym zarządzaniem stanem w Angularze. Ta progresja odzwierciedla trwające wysiłki na rzecz usprawnienia rozwoju Angulara, czyniąc go bardziej przystępnym i wydajnym dla deweloperów.

Ogólne zastosowanie

@ngrx/signals to nie tylko kolejna biblioteka do zarządzania stanem; to zmiana paradygmatu w podejściu deweloperów do stanu w Angularze. Jej zakres zastosowania jest szeroki i wszechstronny, odpowiadając na zróżnicowane potrzeby nowoczesnego rozwoju aplikacji.

Podstawowa implementacja: Głównym atutem @ngrx/signals jest jej intuicyjna implementacja. Bezpośrednia integracja z podstawowymi funkcjami Angulara oferuje znajome, a jednak innowacyjne podejście do zarządzania stanem. Deweloperzy mogą wykorzystać swoje istniejące doświadczenie w Angularze, aby wykorzystać moc @ngrx/signals, doświadczając mieszanki znajomości i innowacji.

Integracja z funkcjami Angulara: Poza podstawową implementacją, @ngrx/signals wyróżnia się swoją synergia z szerszym ekosystemem Angulara. Wzmacnia funkcjonalność komponentów i serwisów, zapewniając płynne doświadczenie w tworzeniu aplikacji. Ta integracja ułatwia bardziej spójną architekturę aplikacji, gdzie zarządzanie stanem jest integralną, ale nieinwazyjną częścią ogólnego projektu.

Różnorodne scenariusze zastosowań: Elastyczność @ngrx/signals jest widoczna w jej zastosowaniu w szerokim spektrum scenariuszy rozwoju. Zręcznie radzi sobie ze stanem w mniejszych aplikacjach, oferując prostotę i szybkość. Jej solidność i skalowalność wychodzą na pierwszy plan w większych, bardziej skomplikowanych systemach, skutecznie zarządzając złożonymi dynamikami stanu. @ngrx/signals oferuje przewagę wydajnościową, zapewniając, że zarządzanie stanem jest responsywne i efektywne.

W następnych sekcjach zbadamy niezrównaną elastyczność @ngrx/signals i jak można ją dostosować do różnych wymagań projektowych.

Techniczne Pogłębienie: Zawiłości @ngrx/signals

Projektowanie Funkcji Fabrycznych

Funkcja signalStore w @ngrx/signals to mistrzostwo w projektowaniu funkcji fabrycznych. Przeciążona, aby wspierać różne poziomy złożoności funkcji, umożliwia tworzenie wysoce konfigurowalnych store’ów. To projektowanie pokazuje elastyczność biblioteki, odpowiadając na różnorodne potrzeby zarządzania stanem.

Kompozycja Funkcji i Redukcja

Kluczową cechą signalStore jest jej zdolność do komponowania funkcji. Każda funkcja reprezentuje modułową część logiki store, którą signalStore płynnie łączy w jednolite, efektywne rozwiązanie do zarządzania stanem. To podejście kompozycyjne jest przykładem nowoczesnych zasad projektowania oprogramowania, podkreślając modularność i możliwość ponownego użycia.

Bezpieczeństwo typów

@ngrx/signals wykorzystuje TypeScript, aby wymusić bezpieczeństwo typów, co jest kluczowym aspektem dla rozwoju aplikacji na dużą skalę. Zapewnia to, że deweloperzy mogą dokładnie kształtować strukturę swojego store’a, znacznie zmniejszając ryzyko błędów czasu wykonania i zwiększając możliwości utrzymania.

Integracja z Ekosystemem Angulara

Wyjątkową cechą signalStore jest jej głęboka integracja z podstawowymi funkcjami Angulara, takimi jak wstrzykiwanie zależności i cykl życia. Zapewnia to, że @ngrx/signals jest zgodny ze wzorcami rozwoju Angulara, co czyni go naturalnym wyborem dla deweloperów.

Porównanie z innymi rozwiązaniami do zarządzania stanem

NgRx Store

  • Złożoność i Boilerplate: Chociaż NgRx Store oferuje wszechstronny wzorzec podobny do Reduxa, często wymaga więcej boilerplate’u i konfiguracji, co czyni go bardziej złożonym. @ngrx/signals, w przeciwieństwie, upraszcza zarządzanie stanem z mniejszą ilością kodu boilerplate i bardziej bezpośrednimi aktualizacjami stanu.
  • Krzywa uczenia się: NgRx Store ma stromszą krzywą uczenia się ze względu na jego skomplikowane wzorce (akcje, reducery, efekty, selektory), podczas gdy @ngrx/signals jest bardziej dostępny, szczególnie dla deweloperów nowych w zarządzaniu stanem.

@ngrx/component-store

  • Zakres użycia: @ngrx/component-store jest zaprojektowany głównie do zarządzania stanem na poziomie komponentu. @ngrx/signals natomiast rozszerza swoją użyteczność zarówno na zarządzanie stanem na poziomie komponentu, jak i globalne, oferując bardziej wszechstronne rozwiązanie.
  • API i projekt: @ngrx/signals wprowadza bardziej funkcyjny styl programowania w porównaniu do @ngrx/component-store.
  • Modułowość: w SignalStore możemy podzielić naszą implementację na oddzielne bloki budowlane, takie jak aktualizatory, efekty uboczne, computed, gdzie każdy z nich może być w oddzielnym pliku, jeśli jest to potrzebne. Nie jest to możliwe w component store, co często prowadzi do szybkiego wzrostu component store finalnie często czyniąc go bardzo trudnym w zarządzaniu.

Porównanie z Akitą i NGXS

  • Prostota: Zarówno Akita, jak i NGXS zapewniają potężne abstrakcje do zarządzania stanem, ale mogą być bardziej skomplikowane i bogate w funkcje. @ngrx/signals skupia się na prostocie i łatwości użytkowania, oferując chudsze rozwiązanie dla wielu aplikacji.
  • Podejście funkcjonalne: @ngrx/signals wyróżnia się swoim funkcjonalnym podejściem do obsługi zmian stanu, odróżniając się od bardziej obiektowych podejść Akity i NGXS.
  • Rozszerzalność: W porównaniu do zarządzania stanem opartym na klasach jest rozszerzalność (Nie możemy rozszerzyć wielu klas za pomocą podejścia opartego na klasach).

Kluczowe Komponenty @ngrx/signals

signalStore

signalStore to kluczowa funkcja, która tworzy nowego store’a. Łączy różne funkcje i fragmenty stanu w jeden store. Możesz myśleć o tym jak o kontenerze, który łączy wszystkie części zarządzania twoim stanem.

Powyżej signalStore jest wykorzystywane do instancjonowania CartStore globalnie. Konfiguracja Wstrzykiwania Zależności (DI), jako opcjonalny pierwszy parametr funkcji, pozwala na zdefiniowanie w jaki sposób nasz store ma być provide’owany. Ta konfiguracja DI odzwierciedla konwencjonalną konfigurację serwisu w Angularze, używając właściwości providedIn dekoratora @Injectable.

withState

withState inicjuje i konfiguruje fragmenty stanu w store, zasadniczo ustawiając domyślny stan aplikacji lub konkretnych funkcji. Jest fundamentalne dla definiowania początkowych wartości stanu.

W tym przykładzie, withState inicjuje cartItems jako pustą tablicę.

withComputed

withComputed jest wykorzystywane do definiowania dynamicznych właściwości, które automatycznie aktualizują się w odpowiedzi na zmiany w stanie, usprawniając tworzenie reaktywnych zależności stanu.

Ten fragment kodu demonstruje obliczaną właściwość cartItemsCount, która zależy od cartItems.

withMethods

withMethods wzbogaca store poprzez dodawanie funkcjonalnych metod aktualizacji stanu lub efektów ubocznych, enkapsulując skomplikowane mutacje stanu w zarządzalne operacje.

W powyższym przykładzie, addItemToCart jest metodą, która aktualizuje stan poprzez dodanie nowego przedmiotu do cartItems.

patchState

patchState służy jako kluczowe narzędzie w Signal Store do aktualizacji stanu, ułatwiając bezpośrednie modyfikacje lub operacje transformacyjne, jednocześnie zachowując niemutowalność i integralność stanu.

Możemy wykorzystać funkcję na różne sposoby. W zakresie naszych metod zdefiniowanych w ramach withMethods

lub bezpośrednio w komponencie, który korzysta z naszego store’a

withHooks

withHooks pozwala dołączyć cykl życia do inicjowania własnej logiki w krytycznych fazach takich jak inicjalizacja (onInit) i destrukcja (onDestroy) store’a, dopasowując zarządzanie stanem do mechanizmów cyklu życia Angulara.

Deklarowanie Signal Store

Łącząc wszystkie powyższe elementy, możemy zadeklarować Signal Store. Może być zadeklarowany podobnie do klasycznego serwisu. Store może być zdefiniowany w swoim własnym dedykowanym pliku, oferując modularność i możliwość ponownego użycia. W zależności od architektury aplikacji, może być dostarczany globalnie lub ograniczony do konkretnych modułów/komponentów. Oto przykład naszego store’a z koszykiem:

W tej deklaracji używamy withState, withComputed, withMethods i withHooks do zdefiniowania stanu, obliczanych właściwości i metod store’a.

Wstrzykiwanie Store

Zadeklarowany store może być wstrzyknięty do komponentów lub serwisów, w miarę potrzeb.

W tym przykładzie, CartStore jest wstrzykiwany do komponentu, zapewniając łatwy dostęp do metod i właściwości store’a.

Rozszerzanie Serwisu za pomocą Signal Store

Signal Store może być używany do rozszerzania istniejących serwisów Angulara, dodając do nich możliwości zarządzania stanem:

To podejście pozwala na integrację zarządzania stanem bezpośrednio w serwisach, wykorzystując moc i prostotę @ngrx/signals.

W tym przykładzie możemy zobaczyć istotę signalStore – modularność i prostotę komponowania store’a dzięki podejściu funkcyjnemu. Wykorzystując funkcję dostarczoną przez bibliotekę, stworzyliśmy prosty store odpowiedzialny za zarządzanie CartItems, który jest niezwykle łatwy do dalszego rozszerzenia.

withEntities

Jak wielu z nas, którzy korzystali z @ngrx/store zna, @ngrx/entity oferujący solidne API, które znacznie usprawnia manipulację i zapytania dotyczące kolekcji encji. Znacząco redukuje powtarzalny kod, obsługując typowe operacje, takie jak dodawanie, aktualizowanie i usuwanie elementów z kolekcji, ułatwiającym tym samym utrzymanie kodu i zwięzłość. Co więcej, jego wbudowane selektory ułatwiają łatwe zapytania i wybór stanu, upraszczając interakcje ze skomplikowanymi strukturami danych.

Budując na tym fundamencie, @ngrx/signals wprowadza withEntities, które jeszcze bardziej upraszcza zarządzanie kolekcjami encji w stanie. Ustanawia mapę encji i tablicę identyfikatorów encji, wraz z computed sygnałami dla bezproblemowego dostępu do list encji. To uproszczone podejście wzmacnia operacje takie jak dodawanie, usuwanie i aktualizowanie elementów. Zaadaptujmy nasz poprzedni przykład, aby wykorzystać withEntities:

Ten przykład podkreśla łatwość, z jaką withEntities ułatwia zarządzanie encjami. Automatycznie tworzone selektory efektywnie pobierają kolekcje encji, podczas gdy zestaw funkcji narzędziowych, w tym addEntity, addEntities, setEntity, i setEntities, zarządza cyklem życia encji w storze. Niezależnie od tego, czy dodajesz, aktualizujesz czy usuwasz encje, funkcje takie jak updateEntity, updateEntities, removeEntity, i removeEntities podążają za intuicyjnymi wzorcami, czyniąc zarządzanie stanem bardziej wydajnym i przyjaznym dla deweloperów.

Elastyczność

Wyróżniającą cechą @ngrx/signals jest jego niezrównana elastyczność, sprawiająca, że jest idealnie dopasowany do praktycznie każdego projektu Angular.

Rozszerzalność: signal store jest zaprojektowany z myślą o rozszerzalności. Pozwala deweloperom budować na jego fundamencie, tworząc niestandardowe rozszerzenia, które odpowiadają na specyficzne potrzeby projektu. Ta adaptacyjność oznacza, że @ngrx/signals może ewoluować wraz z twoim projektem, dostosowując się do nowych wymagań i scenariuszy, które się pojawiają.

Kompatybilność z innymi systemami zarządzania stanem: Jednym z najbardziej przekonujących aspektów @ngrx/signals jest jego zdolność do integracji z innymi systemami zarządzania stanem, takimi jak NgRx czy NGXS. Ta kompatybilność zapewnia, że może być ono bezproblemowo włączone do istniejących projektów bez konieczności przeprojektowania całej architektury zarządzania stanem. Działa jako most, łączący różne systemy pod spójnym, funkcjonalnym podejściem.

Dostosowanie do różnych potrzeb projektów: Każdy projekt ma swój unikalny zestaw wymagań i wyzwań. @ngrx/signals uznaje tę różnorodność, oferując zestaw opcji dostosowania. Niezależnie od tego, czy pracujesz nad aplikacją małej skali, czy dużym systemem korporacyjnym, @ngrx/signals można dostosować do konkretnych potrzeb twojego projektu, zapewniając, że zarządzanie stanem jest zawsze zgodne z twoimi celami deweloperskimi.

Wnioski

Podsumowując, @ngrx/signals pojawia się jako transformacyjne i innowacyjne podejście do zarządzania stanem w aplikacjach Angular. Ta biblioteka redefiniuje tradycyjne praktyki, wprowadzając funkcjonalną, elastyczną i mniej rozwlekłą metodę zarządzania stanem. Współgra bezproblemowo z podstawowymi funkcjami Angulara, umożliwiając deweloperom efektywne zarządzanie stanem zarówno w projektach małej skali, jak i skomplikowanych aplikacjach.

Poprzez porównanie z innymi rozwiązaniami do zarządzania stanem, @ngrx/signals wyróżnia się jako bardziej dostępna i mniej wymagająca opcja, odpowiednia dla szerokiego zakresu scenariuszy deweloperskich. Dogłębne spojrzenie na jego kluczowe komponenty, takie jak signalStore, withState, withComputed i rxMethod, podkreśla jego wszechstronność i moc.

@ngrx/signals wyróżnia się nie tylko ze względu na swoje zasługi techniczne, ale także za swój wkład w bardziej uporządkowany i przyjazny dla deweloperów krajobraz Angular. Oferuje przekonującą opcję dla deweloperów szukających efektywnego, nowoczesnego podejścia do zarządzania stanem, obiecując znaczące usprawnienie w kontekście tworzenia aplikacji w Angularze.

W miarę ewolucji Angulara, @ngrx/signals jest gotowe do odegrania kluczowej roli w kształtowaniu przyszłości zarządzania stanem w tym frameworku.

W przyszłych artykułach zagłębię się w dwa złożone, lecz satysfakcjonujące aspekty @ngrx/signals. Po pierwsze, niestandardowe funkcje store’a wykorzystują signalStoreFeature do rozszerzenia podstawowej funkcjonalności i enkapsulacji wspólnych wzorców, oferując uporządkowane podejście do ulepszania aplikacji Angular. Po drugie, integracja RxJS za pomocą rxMethod pokazuje synergii między reaktywnym programowaniem RxJS a zarządzaniem stanem w signal store. Oba elementy przyczyniają się do bardziej solidnych, utrzymywalnych i wydajnych doświadczeń w tworzeniu aplikacji i zasługują na dokładne zbadanie, aby w pełni wykorzystać ich potencjał w poprawie wydajności i responsywności aplikacji Angular.

O autorze

Mateusz Stefańczyk

Angular Team Leader w House of Angular. Zapalony redaktor angular.love. W portalu od wielu lat. Miłośnik konsol maści wszelakiej i najróżniejszych indyczków 🙂 Fan piłki nożnej zarówno tej prawdziwej, jak i wirtualnej. Każdego weekendu siada głęboko w fotelu, zapina pasy i rozkoszuje się europejskimi rozgrywkami.

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.

2 komentarzy

Dodaj komentarz

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