1. ホーム
  2. angular

[解決済み] RouterModule.forRoot(ROUTES) vs RouterModule.forChild(ROUTES)の比較。

2022-05-04 18:39:47

質問

この2つの違いと、それぞれのユースケースについて教えてください。

その ドキュメント は、必ずしも参考にならない。

forRoot は、すべてのディレクティブ、与えられた ルート、そしてルーターサービス自体です。

forChild は、以下のようなモジュールを作成します。 は、すべてのディレクティブと与えられたルートを含みますが ルーターサービス

私の漠然とした推測では、1つは「メイン」モジュール用で、もう1つはインポートされたモジュール用(メインモジュールから利用できるサービスをすでに持っているから)だと思いますが、実際には使用例を思いつきません。

解決方法は?

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

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

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

@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}]
    };
}