Jakie są różnice między tymi dwoma i jakie są przypadki użycia dla każdego z nich?
W docs nie są dokładnie pomocne:
forRoot tworzy moduł, który zawiera wszystkie dyrektywy, podane trasy i samą usługę routera.
forChild tworzy moduł, który zawiera wszystkie dyrektywy i podane trasy, ale nie zawiera usługi routera.
Moje niejasne przypuszczenie jest takie, że jeden jest przeznaczony dla modułu „głównego”, a drugi dla dowolnych zaimportowanych modułów (ponieważ mieliby już dostępną usługę z modułu głównego), ale tak naprawdę nie mogę wymyślić przypadku użycia.
RouterService
dla jednej aplikacji Angular2.forRoot
zainicjuje tę usługę i zarejestrować go do DI razem z jakimś config trasy, podczas gdyforChild
zarejestruje tylko dodatkowe configs trasy i powiedzieć Angular2 aby ponownie wykorzystaćRouterService
, któreforRoot
stworzył.Odpowiedzi:
Gorąco zachęcam do przeczytania tego artykułu:
Moduł z dostawcami
Podczas importu modułu zwykle używasz odwołania do klasy modułu:
W ten sposób wszyscy dostawcy zarejestrowani w module
A
zostaną dodani do wtryskiwacza root i będą dostępni dla całej aplikacji.Ale jest inny sposób zarejestrowania modułu u dostawców takich jak ten:
Ma to takie same konsekwencje, jak poprzednie.
Prawdopodobnie wiesz, że leniwie ładowane moduły mają swój własny iniektor. Więc przypuśćmy, że chcesz zarejestrować się,
AService
aby być dostępnym dla całej aplikacji, ale niektóre,BService
aby były dostępne tylko dla leniwie ładowanych modułów. Możesz refaktoryzować swój moduł w następujący sposób:Teraz
BService
będzie dostępna tylko dla leniwych załadowanych modułów podrzędnych iAService
będzie dostępna dla całej aplikacji.Możesz przepisać powyższe jako wyeksportowany moduł w następujący sposób:
Jak to się ma do RouterModule?
Załóżmy, że dostęp do nich odbywa się za pomocą tego samego tokena:
Dzięki oddzielnym konfiguracjom, gdy żądasz
token
od leniwego załadowanego modułu, otrzymaszBService
tak, jak planowano.RouterModule używa
ROUTES
tokena, aby uzyskać wszystkie trasy właściwe dla modułu. Ponieważ chce, aby trasy specyficzne dla leniwie ładowanego modułu były dostępne w tym module (analogia do naszego BService), używa innej konfiguracji dla leniwie ładowanych modułów potomnych:źródło
forRoot
modułu ładowanego z opóźnieniem spowoduje utworzenie nowych wystąpień wszystkich usług globalnych w wtryskiwaczu modułu ładowanego z opóźnieniem. Tak, doprowadzi to do nieprzewidywalnych rezultatów. Przeczytaj także ten artykuł Unikanie częstych nieporozumień z modułami w AngularMyślę, że odpowiedzi są prawidłowe, ale myślę, że czegoś brakuje.
To, czego brakuje, to „dlaczego i co rozwiązuje?”.
Ok zaczynajmy.
Najpierw wspomnijmy o kilku informacjach:
Wszystkie moduły mają dostęp do usług root.
Więc nawet leniwie ładowane moduły mogą korzystać z usługi dostarczonej w
app.module
.Co się stanie, jeśli leniwie ładowany moduł zapewni sobie usługę, którą dostarczył już moduł aplikacji? będą 2 wystąpienia.
To nie jest problem, ale czasami jest .
Jak możemy to rozwiązać? po prostu nie importuj modułu z tym dostawcą do modułów ładowanych z opóźnieniem.
Koniec opowieści.
To ^ miało tylko pokazać, że moduły ładowane z opóźnieniem mają swój własny punkt wstrzykiwania (w przeciwieństwie do modułów ładowanych z opóźnieniem).
Ale co się stanie, gdy udostępniony (!) Moduł zadeklaruje
providers
, a ten moduł zostanie zaimportowany przez lazy iapp.module
? Znowu, jak powiedzieliśmy, dwa przypadki.Jak więc możemy rozwiązać ten problem we współdzielonym module POV? Potrzebujemy sposobu, aby nie używać
providers:[]
! Czemu? ponieważ zostaną one automatycznie zaimportowane zarówno do zużywającego lazy, jak i do modułu app.module, a nie chcemy tego, ponieważ widzieliśmy, że każdy będzie miał inną instancję.Cóż, okazuje się, że możemy zadeklarować współdzielony moduł, który nie będzie miał
providers:[]
, ale nadal będzie dostarczał dostawców (przepraszam :))W jaki sposób? Lubię to :
Uwaga, brak dostawców.
Ale
co się stanie teraz, gdy app.module zaimportuje udostępniony moduł z punktem widzenia usługi? NIC.
co się stanie teraz, gdy leniwy moduł zaimportuje moduł współdzielony z POV usługi? NIC.
Wchodzenie do mechanizmu ręcznego poprzez konwencję:
Zauważysz, że dostawcy na zdjęciach mają
service1
iservice2
To pozwala nam na importowanie
service2
dla leniwie ładowanych modułów iservice1
dla nieleniwych modułów. ( kaszel ... router ... kaszel )BTW, nikt nie powstrzymuje Cię przed wywołaniem
forRoot
w leniwym module. ale będziesz mieć 2 instancje, ponieważapp.module
też powinieneś to robić - więc nie rób tego w leniwych modułach.Ponadto - jeśli
app.module
wywołujeforRoot
(i nikt nie dzwoniforchild
) - w porządku, ale iniektor root będzie miał tylkoservice1
. (dostępne dla wszystkich aplikacji)Dlaczego więc tego potrzebujemy? Powiedziałbym :
Otóż to.
Cóż - jest to ukryte w zdaniu powyżej ^
Konwencja (!!!) pozwala to być pojedyncza - albo dokładniej - jeśli nie będą postępować zgodnie z konwencją - będziesz NIE dostać pojedyncza.
Więc jeśli załadować tylko
forRoot
wapp.module
, a następnie dostać tylko jedną instancję, bo tylko powinien wezwaćforRoot
go wapp.module
.Swoją drogą - w tym miejscu można o tym zapomnieć
forChild
. leniwie ładowany moduł nie powinien / nie dzwoniforRoot
- więc jesteś bezpieczny w POV singletona.forRoot i forChild to nie jeden nierozerwalny pakiet - po prostu nie ma sensu wywoływać Roota, który oczywiście będzie ładowany tylko
app.module
bez możliwości leniwych modułów, ma własne usługi, bez tworzenia nowych usług-które-powinny-być -singel.Konwencja ta daje fajną możliwość zwaną
forChild
- konsumować "usługi tylko dla leniwie ładowanych modułów".Oto wersja demonstracyjna Dostawcy root zwracają liczby dodatnie, moduły ładowane z opóźnieniem dają liczby ujemne.
źródło
Dokumentacja jasno określa, jaki jest cel tego rozróżnienia tutaj: https://angular.io/docs/ts/latest/guide/ngmodule.html#!#core-for-root
Każda aplikacja ma dokładnie jeden punkt początkowy (root), w którym powinna zostać zainicjowana główna usługa routingu
forRoot
, natomiast trasy dla poszczególnych funkcji „podrzędnych” powinny być dodatkowo rejestrowane za pomocąforChild
. Jest to niezwykle przydatne w przypadku modułów podrzędnych i leniwie ładowanych modułów, które nie muszą być ładowane przy starcie aplikacji, a jak powiedział @Harry Ninh, powiedziano im, aby ponownie użyli RouterService zamiast rejestracji nowej usługi, co może spowodować błąd w czasie wykonywania.źródło
Jeśli appRoutes zawiera ścieżkę do różnych funkcji w serwisie (admin crud, user crud, book crud) i chcemy je oddzielić, możemy to zrobić po prostu:
A dla tras:
źródło