RouterModule.forRoot (ROUTES) vs RouterModule.forChild (ROUTES)


113

Bu ikisi arasındaki farklar nelerdir ve her birinin kullanım durumları nelerdir?

Docs tam olarak yararlı değildir:

forRoot, tüm yönergeleri, verilen yolları ve yönlendirici hizmetinin kendisini içeren bir modül oluşturur.

forChild, tüm yönergeleri ve verilen yolları içeren, ancak yönlendirici hizmetini içermeyen bir modül oluşturur.

Benim belirsiz tahminim, birinin 'ana' modül için olduğu ve diğerinin herhangi bir içe aktarılan modül için olduğu (çünkü ana modülden zaten hizmete sahip olacakları için), ancak gerçekten bir kullanım durumu düşünemiyorum.


1
Neyi anlamadığın konusunda daha açık konuşabilir misin? Eklediğiniz alıntı, size tam anlamıyla farkın ne olduğunu söyler.
jonrsharpe

2
.ForChild () kullanmanın amacının ne olduğunu anlamıyorum. Servis olmadan direktifleri ve rotaları ne zaman isteyebilirim? Bu arada, lütfen gönderiden sildiğiniz soruyu cevaplayın ...
VSO

19
RouterServiceTek bir Angular2 uygulaması için yalnızca bir tane olmalıdır. forRootiken, bu hizmeti başlatmak ve bazı rota yapılandırma ile birlikte DI bunu kaydedecektir forChildsadece ek rota yapılandırmaları kaydetmek ve yeniden Angular2 söyleyecektir RouterServiceo forRootyaratmıştır.
Harry Ninh

@HarryNinh: Teşekkürler - aradığım buydu. İlk kayıt dışında ek yolları ne zaman kaydetmek istersiniz? Biraz aptalca görünüyor. Dinamik olarak rotalar oluşturmanın bir yolu olmadığını tahmin ediyorum.
VSO

1
bunu açısal yönlendirici yazar Victor tarafından görün .
nikhil mehta

Yanıtlar:


125

Bu makaleyi okumanızı şiddetle tavsiye ediyorum:

Sağlayıcılarla modül

Bir modülü içe aktardığınızda, genellikle modül sınıfına bir başvuru kullanırsınız:

@NgModule({
    providers: [AService]
})
export class A {}

-----------------------------------

@NgModule({
    imports: [A]
})
export class B

Bu şekilde, modüle kayıtlı tüm sağlayıcılar Akök enjektöre eklenecek ve tüm uygulama için kullanılabilir olacaktır.

Ancak bunun gibi sağlayıcılarla bir modül kaydetmenin başka bir yolu var:

@NgModule({
    providers: [AService]
})
class A {}

export const moduleWithProviders = {
    ngModule: A,
    providers: [AService]
};

----------------------

@NgModule({
    imports: [moduleWithProviders]
})
export class B

Bu, öncekiyle aynı çıkarımlara sahiptir.

Muhtemelen tembel yüklü modüllerin kendi enjektörlerine sahip olduğunu biliyorsunuzdur. Öyleyse AService, tüm uygulama için kullanılabilir olmak için kaydolmak istediğinizi , ancak bazılarının BServiceyalnızca tembel yüklü modüller için mevcut olmasını istediğinizi varsayalım . Modülünüzü şu şekilde yeniden düzenleyebilirsiniz:

@NgModule({
    providers: [AService]
})
class A {}

export const moduleWithProvidersForRoot = {
    ngModule: A,
    providers: [AService]
};

export const moduleWithProvidersForChild = {
    ngModule: A,
    providers: [BService]
};

------------------------------------------

@NgModule({
    imports: [moduleWithProvidersForRoot]
})
export class B

// lazy loaded module    
@NgModule({
    imports: [moduleWithProvidersForChild]
})
export class C

Artık BServiceyalnızca yavaş yüklenen alt modüller AServiceiçin geçerli olacak ve tüm uygulama için geçerli olacak.

Yukarıdakileri dışa aktarılan bir modül olarak şu şekilde yeniden yazabilirsiniz:

@NgModule({
    providers: [AService]
})
class A {
    forRoot() {
        return {
            ngModule: A,
            providers: [AService]
        }
    }

    forChild() {
        return {
            ngModule: A,
            providers: [BService]
        }
    }
}

--------------------------------------

@NgModule({
    imports: [A.forRoot()]
})
export class B

// lazy loaded module
@NgModule({
    imports: [A.forChild()]
})
export class C

Bunun RouterModule ile ne ilgisi var?

Her ikisine de aynı jeton kullanılarak erişildiğini varsayalım:

export const moduleWithProvidersForRoot = {
    ngModule: A,
    providers: [{provide: token, useClass: AService}]
};

export const moduleWithProvidersForChild = {
    ngModule: A,
    providers: [{provide: token, useClass: BService}]
};

Ayrı yapılandırmalarla, tokentembel yüklü bir modülden talep ettiğinizde, BServicetam planlandığı gibi alacaksınız .

RouterModule, ROUTESbir modüle özgü tüm yolları almak için belirteç kullanır . Geç yüklü modüle özgü yolların bu modül içinde mevcut olmasını istediğinden (BService analoglarımız), tembel yüklü alt modüller için farklı konfigürasyon kullanır:

static forChild(routes: Routes): ModuleWithProviders {
    return {
        ngModule: RouterModule, 
        providers: [{provide: ROUTES, multi: true, useValue: routes}]
    };
}

3
başka bir deyişle, özellik modüllerinde forChild () 'i çağırmalıyız çünkü forRoot () zaten kök modülde çağrılmış ve gerekli tüm hizmetler eklenmiştir. Yani forRoot () 'u tekrar çağırmak öngörülemeyen durumlara yol açacak mı?
Wachburn

7
@Wachburn, forRoottembel yüklü bir modülü çağırmak , tembel yüklenen modül enjektöründeki tüm küresel hizmetlerin yeni örneklerini oluşturacaktır. Evet, bu öngörülemeyen sonuçlara yol açacaktır. Ayrıca Angular
Max Koretskyi'deki

1
@Willwsharp, neden?
Max Koretskyi

1
Bunu tamamen anlıyorum. Fakat Routermodule.foRoot, VS Routermodule.forChild arasındaki fark nedir? forRoot & forChild, geçirilen değere göre karşılığında nesne veren statik yöntemdir. Peki uygulama modülünde neden forChild kullanamıyorum ?? neden fırlatma hatası? Neden birden fazla forRoot kullanamıyorum?
Subhadeep

2
Bazen cevaplarla doğrudan konuya gitmek iyidir. bilgi yüklenmesi çoğu zaman daha fazla kafa karışıklığına yol açar.
Adépòjù Olúwáségun

33

Cevapların doğru olduğunu düşünüyorum ama bir şeylerin eksik olduğunu düşünüyorum.
Eksik olan şey "neden ve neyi çözüyor?"
Tamam hadi başlayalım.

Öncelikle bazı bilgilerden bahsedelim:

Tüm modüllerin kök hizmetlere erişimi vardır.
Böylece tembel yüklenen modüller bile içinde sağlanan bir hizmeti kullanabilir app.module.
Geç yüklü bir modül, uygulama modülünün zaten sağladığı bir hizmeti kendisine sağlarsa ne olur? 2 örnek olacak .
Sorun değil ama bazen öyle .
Bunu nasıl çözebiliriz? bu sağlayıcı ile bir modülü geç yüklenen modüllere aktarmayın.

Hikayenin sonu.

Bu sadece tembel yüklü modüllerin kendi enjeksiyon noktalarına sahip olduğunu göstermekti (tembel olmayan yüklü modüllerin aksine).

Ancak paylaşılan (!) Bir modül bildirildiğinde providersve bu modül tembel ve app.module ? Yine söylediğimiz gibi, iki örnek.

Peki bunu POV paylaşılan modülünde nasıl çözebiliriz? Biz bir yol gerekir değil kullanımına providers:[]! Neden? çünkü hem lazy tüketen hem de app.module'a otomatik olarak aktarılacaklar ve her birinin farklı bir örneğe sahip olacağını gördüğümüz için bunu istemiyoruz.

Görünüşe göre, sahip olmayacak providers:[], ancak yine de sağlayıcı sağlayacak (üzgünüm :))

Nasıl? Bunun gibi :

görüntü açıklamasını buraya girin

Dikkat, sağlayıcı yok.

Fakat

  • app.module paylaşılan modülü hizmet POV ile içe aktarırken şimdi ne olacak? HİÇBİR ŞEY DEĞİL.

  • şimdi, tembel bir modül paylaşılan modülü hizmetin bakış açısı ile içe aktarırsa ne olacak? HİÇBİR ŞEY DEĞİL.

Manuel mekanizmaya kongre yoluyla girme:

Resimlerdeki sağlayıcıların service1veservice2

Bu, service2tembel yüklü modüller ve service1tembel olmayan modüller için içe aktarmamızı sağlar . ( öksürük ... yönlendirici .... öksürük )

BTW, hiç kimse sizi forRoottembel bir modül içinde aramanızı engellemiyor . ancak 2 örneğiniz olacak çünkü app.modulebunu da yapmalısınız - bu yüzden bunu tembel modüllerde yapmayın.

Ayrıca - eğer app.modulearama yaparsa forRoot(ve kimse aramazsa forchild) - sorun değil, ancak kök enjektöründe sadece olacaktır service1. (tüm uygulamalarda kullanılabilir)

Öyleyse neden ihtiyacımız var? Diyecektim ki :

Ortak bir modül, muktedir verir bölmek yoluyla - istekli modülleri ve tembel modüllerle kullanılmak üzere onun farklı-sağlayıcıları forRootve forChildkongre. Tekrar ediyorum: kongre

Bu kadar.

BEKLE !! singleton hakkında tek bir kelime yok mu? Öyleyse neden her yerde singleton okuyorum?

Peki - yukarıdaki cümlede gizlidir ^

ForRoot ve forChild aracılığıyla farklı sağlayıcılarını istekli modüller ve tembel modüllerle kullanılmak üzere bölebilen paylaşılan bir modül sağlar .

Kongre veya daha doğrusu - - Eğer kuralına uyulur etmezse - sen olur (!!!) bu singleton'ununu olmasını sağlayan DEĞİL a tek olsun.
Yalnızca yük Yani forRootiçinde app.module sadece çağırmalıdır çünkü, o zaman yalnızca bir örneğini almak forRooto app.module.
BTW - bu noktada unutabilirsiniz forChild. tembel yüklü modül aramamalı / aramayacaktırforRoot aramamalı / aramamalı - bu nedenle tekil bakış açısıyla güvendesiniz.

forRoot ve forChild tek bir kırılmaz paket değildir - sadece app.module tembel modüller için yetenek vermeden yalnızca yüklenecek olan , olması gereken yeni hizmetler oluşturmadan kendi hizmetlerine sahip olan Root'u çağırmanın bir anlamı yoktur . -singleton.

Bu kural size forChild"yalnızca geç yüklü modüller için hizmetler" tüketme adı verilen güzel bir yetenek verir .

İşte bir demo Kök sağlayıcıları pozitif sayılar verir, tembel yüklü modüller negatif sayılar verir.


1
1. Burada POV nedir? 2. Stackblitz artık çalışmıyor.
Nicholas K

@NicholasK bu stackblitz bir süre sonra her zaman işleri karıştırır. yeni sürümü yüklemeye çalışacağım
Royi Namir

26

Belgeler, burada bu ayrımın amacının ne olduğunu açıkça belirtir: https://angular.io/docs/ts/latest/guide/ngmodule.html#!#core-for-root

ForRoot'u yalnızca kök uygulama modülü olan AppModule'da arayın. Başka herhangi bir modülde, özellikle de tembel yüklü bir modülde çağırmak, amaca aykırıdır ve muhtemelen bir çalışma zamanı hatası üretecektir.

Sonucu içe aktarmayı unutmayın; başka bir @NgModule listesine eklemeyin.

Her uygulamanın tam olarak bir başlangıç ​​noktası (kök) vardır ve burada ana yönlendirme hizmetinin başlatılması forRootgerekirken, belirli "alt" özellikler için yollar ek olarak kaydedilmelidir forChild. Uygulama başlangıcında yüklenmesi gerekmeyen alt modüller ve tembel yüklü modüller için son derece kullanışlıdır ve @Harry Ninh'in söylediği gibi, yeni hizmetin kaydı yerine RouterService'i yeniden kullanmaları söylendi, bu da çalışma zamanı hatasına neden olabilir.


2
Bu belgeler taşınmış gibi görünüyor, v2.angular.io/docs/ts/latest/guide/…
PeterS

1

AppRoutes, sitedeki çeşitli işlevlere (yönetici pisliği, kullanıcı pisliği, kitap pisliği) giden bir yol içeriyorsa ve bunları ayırmak istiyorsak, bunu basitçe yapabiliriz:

 imports: [
    BrowserModule, HttpModule,
    AppRoutingModule,
    RouterModule.forRoot(categoriesRoutes),
    RouterModule.forRoot(auteursRoutes),
  ],

Ve rotalar için:

const auteursRoutes:Routes=[
  {path:'auteurs/ajouter',component:CreerAuteurComponent},
]
const categoriesRoutes: Routes = [


  {path:'categories/consulter',component:ConsultercategoriesComponent},
  {path:'categories/getsouscategoriesbyid/:id',component:GetsouscategoriesbyIDComponent},
  {path:'categories/ajout',component:CreerCategorieComponent},
 {path:'categories/:id',component:ModifiercategorieComponent},
 {path:'souscategories/ajout/:id',component:AjoutersouscategorieComponent},
 {path:'souscategories/lecture/:id1',component:SouscategoriesComponent},
 {path:'souscategories/modifier/:id1',component:ModifiersupprimersouscategorieComponent},
  {path:'uploadfile',component:UploadfileComponent},
  {path:'categories',component:ConsultercategoriesComponent},



]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.