RouterModule.forRoot(ROUTES)とRouterModule.forChild(ROUTES)


111

これら2つの違いは何ですか?それぞれのユースケースは何ですか?

ドキュメントは正確に有用ではありません。

forRootは、すべてのディレクティブ、指定されたルート、およびルーターサービス自体を含むモジュールを作成します。

forChildは、すべてのディレクティブと指定されたルートを含むモジュールを作成しますが、ルーターサービスは含みません。

私の漠然とした推測では、1つは「メイン」モジュール用であり、もう1つはインポートされたモジュール用です(メインモジュールから利用可能なサービスがすでにあるため)が、実際の使用例は考えられません。


1
わからないことについて具体的に教えてください。あなたが含めた引用は文字通り違いが何であるかをあなたに伝えます。
jonrsharpe

2
.forChild()を使用する意味がわかりません。サービスなしのディレクティブとルートはいつ必要になりますか?それまでの間、投稿から削除した質問に答えてください...
VSO

18
RouterService単一のAngular2アプリケーションに対して1つだけ存在する必要があります。forRoot一方で、そのサービスを初期化し、いくつかのルートの設定と一緒DIにそれを登録するforChildだけで、追加のルートのconfigsを登録して再利用するAngular2を教えてくれますRouterServiceようforRootに作成しています。
ハリー・ニン

@HarryNinh:ありがとう-それが私が探していたものです。ただし、最初の登録以外の追加のルートをいつ登録したいですか?ちょっとばかげているようです。ルートを動的に作成する方法はないと思います。
VSO 2016年

1
角型ルーターの作者であるビクターによるこれを見てください。
nikhil mehta 2017年

回答:


123

この記事を読むことを強くお勧めします。

プロバイダー付きモジュール

モジュールをインポートするときは、通常、モジュールクラスへの参照を使用します。

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

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

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

このようにして、モジュールに登録されているすべてのプロバイダーAがルートインジェクターに追加され、アプリケーション全体で使用できるようになります。

しかし、このようなプロバイダーにモジュールを登録する別の方法があります:

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

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

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

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

これには、前のものと同じ影響があります。

おそらく、遅延ロードされたモジュールには独自のインジェクターがあることを知っています。したがってAService、アプリケーション全体で使用できるように登録したいが、一部BServiceは遅延ロードされたモジュールでのみ使用できるようにするとします。次のようにモジュールをリファクタリングできます:

@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

これでBService、子の遅延読み込みモジュールでのみAService使用可能になり、アプリケーション全体で使用できるようになります。

上記のように、次のようにエクスポートされたモジュールとして書き換えることができます。

@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

それはどのようにRouterModuleに関連していますか?

同じトークンを使用して両方にアクセスするとします。

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

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

token遅延ロードされたモジュールから要求するときに個別の構成を使用するとBService、計画どおりに取得できます。

RouterModuleはROUTESトークンを使用して、モジュールに固有のすべてのルートを取得します。レイジーロードされたモジュールに固有のルートをこのモジュール(BServiceのアナログ)内で利用できるようにしたいので、レイジーロードされた子モジュールに異なる構成を使用します。

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

3
したがって、言い換えると、機能モジュールでforChild()を呼び出す必要があります。これは、ルートモジュールでforRoot()がすでに呼び出され、必要なすべてのサービスが追加されているためです。したがって、再度forRoot()を呼び出すと、予期しない状態が発生しますか?
Wachburn 2017年

7
@Wachburn、forRoot遅延ロードされたモジュールを呼び出すと、遅延ロードされたモジュールインジェクターにすべてのグローバルサービスの新しいインスタンスが作成されます。はい、これは予期しない結果につながります。また、この記事もお読みください
。Angularの

1
@Willwsharp、なぜ?
Max Koretskyi 2017

1
私はこれを完全に理解しています。しかし、Routermodule.foRootとVS Routermodule.forChildの違いは何ですか?forRoot&forChildは、渡された値に基づいてオブジェクトを返す静的メソッドです。アプリモジュールで、なぜforChildを使用できないのですか?なぜそのスローエラー?複数のforRootを使用できないのはなぜですか?
Subhadeep

2
時々、答えを持って要点にまっすぐ行くのがちょうど良いです。ほとんどの場合、情報過多はさらに混乱を招きます。
AdépòjùOlúwáségun

33

答えは正しいと思いますが、何かが足りないと思います。
欠けているのは「なぜ、何を解決するのか」です。
じゃあ始めよう。

最初にいくつかの情報に触れましょう:

すべてのモジュールがルートサービスにアクセスできます。
したがって、遅延ロードされたモジュールでも、で提供されたサービスを使用できますapp.module
遅延ロードされたモジュールが、アプリモジュールがすでに提供しているサービスをそれ自体に提供するとどうなりますか 2つのインスタンスがあります。
問題ではありませんが、時々問題になります
どうすれば解決できますか?そのプロバイダーのモジュールを遅延読み込みされたモジュールにインポートしないでください。

物語の終わり。

この^は、遅延ロードされたモジュールが(遅延ロードされていないモジュールとは対照的に)独自の注入ポイントを持っていることを示すためだけのものでした。

しかし、shared(!)モジュールが宣言されproviders、そのモジュールがレイジー インポートされるapp.moduleどうなりますか?繰り返しになりますが、2つのインスタンスがあります。

それでは、共有モジュールのPOVでこれをどのように解決できますか?使用しない方法が必要providers:[]です!どうして?これらは消費するレイジーとapp.moduleの両方に自動的にインポートされ、それぞれに異なるインスタンスがあることがわかったので、これは望ましくありません。

まあ、それは私たちが持っていない共有モジュールを宣言できることが判明しましたがproviders:[]、それでもプロバイダーを提供します(すみません:))

どうやって?このような :

ここに画像の説明を入力してください

プロバイダーはありません。

だが

  • app.moduleが共有モジュールをサービスのPOVでインポートするとどうなりますか?何も。

  • レイジーモジュールが共有モジュールをサービスのPOVでインポートするとどうなりますか?何も。

慣習により手動メカニズムに入る:

あなたは、写真の中のプロバイダが持っていることがわかりますservice1し、service2

これによりservice2、遅延ロードされたモジュールおよびservice1非遅延モジュールのインポートが可能になります。(咳...ルーター...咳

ところで、forRoot遅延モジュール内での呼び出しを停止している人はいません。ので、しかし、あなたは2つのインスタンスを持つことになりapp.moduleそう-もそれを行う必要がありません怠惰なモジュールでそれを行います。

また- app.module呼び出した場合forRoot(誰も呼び出さない場合forchild)-それは問題ありませんが、ルートインジェクタにはのみありservice1ます。(すべてのアプリで利用可能)

では、なぜそれが必要なのでしょうか。私は言うでしょう:

それはできるようにするには、共有モジュールを可能に分け経由-熱心モジュールと怠惰なモジュールで使用するその異なる-プロバイダforRootforChild慣習を。繰り返します:慣習

それでおしまい。

待つ !!シングルトンについて一言ではない?? なぜ私はどこでもシングルトンを読むのですか?

まあ-それは上の文に隠されています^

これにより、共有モジュールが、さまざまなプロバイダーを分割して、熱心なモジュールと遅延モジュールで使用できるようになります(forRootおよびforChildを介して)。

大会は(!!!)、それはシングルトンにすることができます-またはより正確に-あなたが慣例に従わない場合-あなたはなりませシングルトンを取得します。
あなたが唯一のロードあればforRootapp.module 、あなただけ呼び出す必要がありますので、あなたは唯一のインスタンスを取得forRootして、それをapp.module
ところで-この時点であなたは忘れることができますforChild。遅延ロードされたモジュールは呼び出すべきではありません/呼び出さないforRootので、シングルトンのPOVで安全です。

forRootとforChildは1つの壊れないパッケージではありません- app.module 遅延モジュールの機能を提供せずにのみロードされ、新しいサービスを作成せずに独自のサービスを提供するRootを呼び出す意味がないだけです。-シングルトン。

この規則により、forChild「遅延ロードされたモジュールのみのサービス」を利用するという優れた機能が提供されます。

以下はデモです。ルートプロバイダーは正の数を生成し、遅延ロードされたモジュールは負の数を生成します。


1. POVとは何ですか?2. stackblitzが機能しなくなりました。
ニコラスK

@NicholasKこのstackblitzは常にしばらくすると混乱します。新しいバージョンをアップロードしよう
Royi Namir

26

ドキュメントには、この区別の目的がここに明確に記載されています:https : //angular.io/docs/ts/latest/guide/ngmodule.html#!#core-for-root

ルートアプリケーションモジュールAppModuleでのみforRootを呼び出します。他のモジュール、特に遅延ロードされたモジュールで呼び出すと、意図に反し、実行時エラーが発生する可能性があります。

結果をインポートすることを忘れないでください。他の@NgModuleリストには追加しないでください。

すべてのアプリケーションには、メインルーティングサービスをで初期化する必要がある開始点(ルート)が1つだけありますがforRoot、特定の「子」機能のルートはで追加登録する必要がありforChildます。これは、アプリケーションの開始時にロードする必要のないサブモジュールと遅延ロードされたモジュールに非常に役立ちます。@ Harry Ninhが言ったように、新しいサービスの登録ではなくRouterServiceを再利用するように指示されているため、ランタイムエラーが発生する可能性があります。


2
これらのドキュメントは移動されたようです、v2.angular.io
docs /

1

appRoutesにサイトのさまざまな機能(admin crud、user crud、book crud)へのパスが含まれていて、それらを分離したい場合は、単純にそれを行うことができます。

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

そしてルートの場合:

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},



]
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.