web-dev-qa-db-ja.com

Angular2で依存性注入(DI)を正しく使用する方法

私は、Angular2で(DI)依存性注入がどのように機能するかを理解しようとしています。コンポーネントにサービスやクラスを挿入しようとするたびに、多くの問題や問題に遭遇しました。

さまざまなグーグルの記事から、コンポーネント構成で_providers: []_を使用する必要があります。または、コンストラクターで@Inject()を使用するか、bootstrap(app, [service])に直接注入する必要があります。また、いくつかの記事で_@injectable_デコレータを配置することを求めています。

たとえば、Httpを注入するには、_import{Http}_だけを使用してプロバイダーにHttpを配置する必要がありますが、FormBuilderでは、コンストラクターで@Inject()を使用する必要があります。

何を使用するかについての経験則はありますか?サンプルコードスニペットを提供してください。ありがとうございました :-)

24
George Huang

Angular2の依存性注入は、コンポーネントのツリーにリンクされている階層的なインジェクターに依存しています。

これは、異なるレベルでプロバイダーを構成できることを意味します。

  • ブートストラップするときのアプリケーション全体。この場合、すべてのサブインジェクター(コンポーネントインジェクター)はこのプロバイダーを参照し、関連付けられたインスタンスを共有します。対話するとき、それは同じインスタンスになります
  • 特定のコンポーネントとそのサブコンポーネント用。前と同じですが、特定のコンポーネント用です。他のコンポーネントはこのプロバイダーを認識しません。上記で定義したものを再定義する場合(たとえば、ブートストラップ時)、代わりにこのプロバイダーが使用されます。だからあなたは物事をオーバーライドすることができます。
  • サービス用。それらに関連付けられたプロバイダーはありません。トリガーする要素からインジェクターのいずれかを使用します(直接=コンポーネントまたは間接=サービスチェーンの呼び出しをトリガーするコンポーネント)

他の質問について:

  • @Injectable。クラスに注入するには、デコレータが必要です。コンポーネントには1つ(@Componentが1つ)がありますが、サービスは単純なクラスです。サービスに依存関係を挿入する必要がある場合、このデコレーターが必要です。
  • @Inject。ほとんどの場合、Angular2が何を注入するかを決定するには、コンストラクターパラメーターのタイプで十分です。場合によっては(たとえば、プロバイダーを登録するためにクラスではなくOpaqueTokenを明示的に使用する場合)、注入するものについてのヒントを指定する必要があります。そのような場合、@ Injectを使用する必要があります。

詳細については、次の質問を参照してください。

13

幅広い質問、TL; DRバージョン


@ Injectable()

  • は、装飾されたクラスにTypeScriptがあることをdependenciesに伝えるデコレーターであり、このクラスを他のクラスに注入できることを意味するものではありません。

  • そして、TypeScriptは、imported依存関係を使用して、構築時に必要なメタデータを装飾されたクラスに挿入する必要があることを理解します。

bootstrap(app、[service])

  • bootstrap()は、ブートストラップされるときにアプリケーションのルートインジェクターを作成します。プロバイダーのリストを2番目の引数として取り、作成時にインジェクターに直接渡します。

  • bootstrap Httpのような多くの場所で使用されるサービスを備えたアプリケーション。これは、クラス構成に_providers: [Http]_を記述する必要がないことも意味します。 。

プロバイダー:[サービス]

  • プロバイダーは、すべてのサービスの引数をInjectorに渡す作業も行います。

  • bootstrap() pedでない場合は、サービスをプロバイダーに配置します。そして、いくつかの場所でのみ必要です。

@ Inject()

  • は また、デコレータ これらのサービスを実際に注入する作業を行う関数
    このような。 constructor(@Inject(NameService) nameService)
  • しかし、TSを使用する場合は、このconstructor(nameService: NameService)だけで、TypeScriptが残りを処理します。

さらに読む

お役に立てれば。 :)

17
Ankit Singh

プロバイダーを使用する必要があります:[]

依存性注入がインスタンスを作成できるようにするには、これらのクラス(または他の値)のプロバイダーを登録する必要がありますsomewhere

プロバイダーを登録する場所によって、作成される値の範囲が決まります。 Angulars DIは階層的です。
ツリーのルートでプロバイダーを登録する場合


> = RC.5

_@NgModule({
  providers: [/*providers*/]
  ...
})
_

または遅延読み込みモジュールの場合

_static forRoot(config: UserServiceConfig): ModuleWithProviders {
  return {
    ngModule: CoreModule,
    providers: [
      {provide: UserServiceConfig, useValue: config }
    ]
  };
}
_

<= RC.4

bootstrap(AppComponent, [Providers})または@Component(selector: 'app-component', providers: [Providers])(ルートコンポーネント)


インスタンスを要求するすべてのコンポーネントとサービスは同じインスタンスを取得します。

プロバイダが子コンポーネントの1つに登録されている場合、このコンポーネントの子孫に新しい(異なる)インスタンスが提供されます。

コンポーネントが(コンストラクターパラメーターによって)インスタンスを要求すると、DIはコンポーネントツリーを「上」に見て(リーフからルートに向かって)、見つけた最初のプロバイダーを取得します。このプロバイダーのインスタンスが既に作成されている場合、このインスタンスが使用されます。それ以外の場合は、新しいインスタンスが作成されます。

@Inject()

コンポーネントまたはサービスがDIに値を要求するとき

_constructor(someField:SomeType) {}
_

DIは、SomeType型でプロバイダーを検索します。 @Inject(SomeType)が追加された場合

_constructor(@Inject(SomeType) someField:SomeType) {}
_

DIは、@Inject()に渡されたパラメーターによってプロバイダーを検索します。上記の例では、@Inject()に渡されるパラメーターはパラメーターの型と同じであるため、@Inject(SomeType)は冗長です。

ただし、構成設定を挿入するなど、動作をカスタマイズする必要がある場合があります。

_constructor(@Inject('someName') someField:string) {}
_

タイプstringは、複数の登録がある場合に特定の構成設定を区別するには不十分です。
構成値は次のようなプロバイダーとして登録する必要があります


> = RC.5

_@NgModule({
  providers: [{provide: 'someName', useValue: 'abcdefg'})]
  ...
})
export class AppModule {}
_

<= RC.4

_bootstrap(AppComponent, [provide('someName', {useValue: 'abcdefg'})])
_

そのため、コンストラクタが次のように見える場合、FormBuilderに対して@Inject()は必要ありません

_constructor(formBuilder: FormBuilder) {}
_
4

他の回答で言及されていないものをいくつか追加します。 (私がこれを書いているとき、それはティエリー、ギュンター、およびA_Singhからの答えを意味します)。

  • 作成するサービスには常にInjectable()を追加してください。サービス自体が何かを挿入する必要がある場合にのみ必要ですが、常に含めることをお勧めします。
  • ディレクティブ/コンポーネントのproviders配列とNgModulesのproviders配列は、組み込みではないプロバイダーを登録する2つの方法です。 (登録する必要のない組み込みオブジェクトの例は、ElementRefApplicationRefなどです。これらを単純に挿入できます。)
  • コンポーネントにproviders配列がある場合、そのコンポーネントはAngularインジェクター。インジェクターは、何かが依存関係(コンストラクターで指定)をインジェクトしたいときに参照されます。インジェクターツリーをコンポーネントツリーよりも予備のツリーと考えるのが好きです。依存関係の要求を満たすことができる最初のインジェクターはそうします。
2
Mark Rajcok

なぜ@Injectable()なのか?

@Injectable()は、インスタンス化のためにインジェクターが使用できるクラスをマークします。一般的に、インジェクターは@Injectable()としてマークされていないクラスをインスタンス化しようとするとエラーを報告します。

たまたま、最初のバージョンのHeroServiceにはパラメーターが挿入されていないため、@ Injectable()を省略できました。しかし、私たちのサービスには依存性が注入されているので、今それが必要です。 AngularはLoggerを注入するためにコンストラクタパラメータメタデータを必要とするため、必要です。

提案:すべてのサービスクラスに@INJECTABLE()を追加するすべてのサービスクラスに@Injectable()を追加することをお勧めします。依存関係がなく、したがって技術的にそれを必要としないものも含めます。その理由は次のとおりです。

将来の証明:後で依存関係を追加するときに@Injectable()を覚えておく必要はありません。

一貫性:すべてのサービスは同じルールに従い、デコレーターが欠落している理由を疑問に思う必要はありません。

インジェクターは、HeroesComponentなどのコンポーネントのインスタンス化も担当します。 HeroesComponentを@Injectable()としてマークしなかったのはなぜですか?

本当に必要な場合は追加できます。 HeroesComponentはすでに@Componentでマークされているため、このデコレータークラス(後で説明する@Directiveや@Pipeなど)はInjectableMetadataのサブタイプであるため、必要ありません。実際、インジェクタによるインスタンス化のターゲットとしてクラスを識別するのは、InjectableMetadataデコレータです。

ソース: https://angular.io/docs/ts/latest/guide/dependency-injection.html

0
stackdave