web-dev-qa-db-ja.com

機能モジュール階層内での.forRoot()の使用方法

誰かが.forRoot()呼び出しで複数のネストされた機能モジュール階層をどのように構成する必要があるかを明確にしてくれますか?

たとえば、次のようなモジュールがある場合はどうなりますか:

- MainModule
- SharedModule
- FeatureModuleA
    - FeatureModuleA1
    - FeatureModuleA2
- FeatureModuleB

すべての機能モジュールには、.forRoot()静的関数があります。

FeatureModuleAを.forRoot()関数を何らかの方法で「転送」して定義するにはどうすればよいですか?

@NgModule({ 
  imports: [
    //- I can use .forRoot() calls here but this module not the root module
    //- I don't need to import sub-modules here, FeatureA only a wrapper
    //FeatureModuleA1.forRoot(), //WRONG!
    //FeatureModuleA2.forRoot(), //WRONG!
  ],
  exports: [
    //I cannot use .forRoot() calls here
    FeatureModuleA1, 
    FeatureModuleA2 
  ]
})
class FeatureModuleA {
  static forRoot(): ModuleWithProviders {
    return {
      //At this point I can set any other class than FeatureModuleA for root
      //So lets create a FeatureRootModuleA class: see below!
      ngModule: FeatureModuleA //should be: FeatureRootModuleA 
    };
  }
}

ルート用に別のクラスを作成し、FeatureModuleAのforRoot()関数内で設定できます。

@NgModule({
  imports: [
    //Still don't need any sub module within this feature module
  ]
  exports: [
    //Still cannot use .forRoot() calls but still need to export them for root module too:
    FeatureModuleA1, 
    FeatureModuleA2 
  ]
})
class FeatureRootModuleA { }

しかし、この特別なModuleClass内で.forRoot()呼び出しを「転送」するにはどうすればよいですか?

ご覧のとおり、すべてのサブモジュールをルートのMainModuleに直接インポートし、それぞれに対して.forRoot()を呼び出す必要があります。

@NgModule({
  imports: [
    FeatureModuleA1.forRoot(),
    FeatureModuleA2.forRoot(),
    FeatureModuleA.forRoot(),
    SharedModule.forRoot()
  ]
})
class MainModule { }

私は正しいですか?答える前に、このファイルを見てください: https://github.com/angular/material2/blob/master/src/lib/module.ts

私が知っているように、このレポは公式のangularチームによって維持されています。したがって、特別なMaterialRootModuleモジュール内ですべての.forRoot()呼び出しをインポートするだけで、上記を解決します。私はそれが自分のルートモジュールにどのように適用されるのか本当に理解していませんか?ここでroot。forRootは本当に何を意味するのでしょうか?実際のWebプロジェクトではなく、パッケージに関連していますか?

53
ggabor

通常、forRootは、アプリケーション/シングルトンサービスを追加するために使用されます。

@NgModule({
  providers: [ /* DONT ADD HERE */ ]
})
class SharedModule {
  static forRoot() {
    return {
      ngModule: SharedModule,
      providers: [ AuthService ]
    }
  }
}

理由は、@NgModuleAuthServiceprovidersを追加すると、SharedModuleを他のモジュールにインポートすると、複数のものが作成される可能性があるためです。

SharedModuleが熱心にロードされたモジュールにインポートされたときにサービスが作成されるかどうかについて100%明確ではありませんが、ドキュメントに記載されている説明は遅延ロードされたモジュールに関するものでした。モジュールを遅延ロードすると、すべてのプロバイダーが作成されます。

このため、(慣例により)forRootメソッドを追加して、メソッドがルート(アプリ)モジュールに対してのみ呼び出され、他のモジュールに対しては通常どおりにインポートされることを示します。

@NgModule({
  imports: [SharedModule]
})
class FeatureModule {}

@NgModule({
  imports: [SharedModule.forRoot()]
})
class AppModule {}
100
Paul Samsotha

forRootはシングルトンサービスの提供のみを目的としているため、SharedModuleで明示的に「再提供」できます。

@NgModule({})
class SharedModule {
  static forRoot() {
    return {
      ngModule: SharedModule,
      providers: [
        AuthService,
        FeatureModuleA.forRoot().providers,
        FeatureModuleB.forRoot().providers,
      ],
    }
  }
}

このように、すべてのサービスはSharedModule自体(それぞれのサブモジュールではなく)によって提供されますが、それは重要ではないようです。たぶん誰かが議論することができます...

FeatureModuleAも同様に、サブモジュールからシングルトンサービスを「再提供」できることに注意してください。

5
Den Klimovsky

上記のように、共有サービスは遅延ロードモジュールで使用できるため、遅延ロードモジュールは考慮する必要がありますが、そのサービスが既に別のモジュールで使用およびインスタンス化されている場合は、2つのインスタンスがあるため、シングルトンパターンが必要です。 AuthServiceはここでの素晴らしい例です-認証されていないユーザーとサービスの1つのインスタンスを持ち、別のインスタンスが「同じ」ユーザーを認証したくない場合。

Angular 6の新機能として、プロバイダーをシングルトンとして登録する新しい方法があります。サービスの@Injectable()デコレータ内で、providedIn属性を使用します。その値を「root」に設定します。その後、ルートモジュールのプロバイダーリストに追加する必要はありません。この場合、次のようにSharedModuleに設定することもできます。

@Injectable({
  providedIn: SharedModule // or 'root' for singleton
})
export class AuthService {
...
1
thenninger