route - angular title service




Wie verwende ich Dependency Injection(DI) in Angular2 richtig? (4)

Ich habe versucht herauszufinden, wie die (DI) Dependency Injection in Angular2 funktioniert. Jedes Mal, wenn ich versuchte, einen Service oder eine Klasse in meine Komponenten einzufügen, gab es viele Probleme.

Aus verschiedenen googelten Artikeln muss ich entweder providers: [] in der Komponentenkonfiguration oder manchmal muss ich @Inject() in meinem Konstruktor verwenden oder direkt in den bootstrap(app, [service]) @Inject() ? Ich habe auch einige Artikel gesehen, in denen ich @injectable decorator setzen @injectable .

Zum Beispiel: Um HTTP zu injizieren, muss ich nur import{Http} und HTTP in die Provider einfügen, aber für FormBuilder muss ich @Inject() im Konstruktor verwenden.

Gibt es eine Faustregel für die Verwendung von was? Könnten Sie bitte ein Beispiel-Code-Snippet bereitstellen? Dankeschön :-)


Ich muss entweder Anbieter verwenden: []

Damit die Abhängigkeitsinjektion Instanzen für Sie erstellen kann, müssen Sie irgendwo Anbieter für diese Klassen (oder andere Werte) registrieren.

Wo Sie einen Provider registrieren, bestimmt der Umfang des erstellten Wertes. Die Winkel DI sind hierarchisch.
Wenn Sie einen Anbieter im Stammverzeichnis des Baums registrieren

> = RC.5

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

oder für faul geladene Module

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

<= RC.4

( bootstrap(AppComponent, [Providers}) oder @Component(selector: 'app-component', providers: [Providers]) (Root-Komponente)

dann erhalten alle Komponenten und Dienste, die eine Instanz anfordern, dieselbe Instanz.

Wenn ein Anbieter in einer der untergeordneten Komponenten registriert ist, wird eine neue (andere) Instanz für Nachkommen dieser Komponente bereitgestellt.

Wenn eine Komponente eine Instanz anfordert (über einen Konstruktorparameter), durchsucht DI den Komponentenbaum (vom Blatt zum Stamm) nach oben und nimmt den ersten Anbieter, den sie findet. Wenn eine Instanz für diesen Anbieter bereits zuvor erstellt wurde, wird diese Instanz verwendet, andernfalls wird eine neue Instanz erstellt.

@Injizieren()

Wenn eine Komponente oder ein Dienst einen Wert von DI wie anfordert

constructor(someField:SomeType) {}

DI sucht den Provider nach dem Typ SomeType . Wenn @Inject(SomeType) hinzugefügt wird

constructor(@Inject(SomeType) someField:SomeType) {}

DI sucht den Provider anhand des an @Inject() Parameters. Im obigen Beispiel entspricht der an @Inject() Parameter dem Parametertyp, daher ist @Inject(SomeType) redundant.

Es gibt jedoch Situationen, in denen Sie das Verhalten anpassen möchten, z. B. um eine Konfigurationseinstellung einzufügen.

constructor(@Inject('someName') someField:string) {}

Die string reicht nicht aus, um eine bestimmte Konfigurationseinstellung zu unterscheiden, wenn mehrere registriert sind.
Der Konfigurationswert muss irgendwo als Provider registriert sein

> = RC.5

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

<= RC.4

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

Daher benötigen Sie @Inject() für FormBuilder wenn der Konstruktor so aussieht

constructor(formBuilder: FormBuilder) {}

Breite Frage, TL; DR- Version

@Injectable()

  • ist ein Dekorator, der dem typescript mitteilt, dass die dekorierte Klasse dependencies und nicht bedeutet, dass diese Klasse in eine andere Klasse injiziert werden kann.

  • Und dann versteht TypeScript, dass es beim Konstruieren die erforderlichen Metadaten unter Verwendung der imported Abhängigkeiten in die dekorierte Klasse einfügen muss.

Bootstrap (App, [Dienst])

  • bootstrap () kümmert sich darum, einen Root-Injektor für unsere Anwendung zu erstellen, wenn dieser gebootet wird. Als zweites Argument wird eine Liste von Anbietern verwendet, die beim Erstellen direkt an den Injektor übergeben wird.

  • Sie booten Ihre Anwendung mit den Diensten, die an vielen Orten wie Http , was auch bedeutet, dass Sie keine providers: [Http] schreiben müssen providers: [Http] in Ihrer Klassenkonfiguration.

Anbieter: [Service]

  • Die Anbieter übernehmen auch die Aufgabe, alle Argumente der Services an Injector .

  • Sie legen Dienste in Providern ab, wenn es nicht bootstrap() ped with ist. Und wird nur an wenigen Stellen benötigt.

@Inject()

  • ist auch ein Dekorateur eine Funktion, die die Arbeit des tatsächlichen Injizierens dieser Dienste erledigt
    so was. constructor(@Inject(NameService) nameService)
  • Wenn Sie jedoch TS verwenden, müssen Sie nur diesen constructor(nameService: NameService) und constructor(nameService: NameService) , um den Rest zu erledigen.

Weitere Lektüre

Hoffe das hilft. :)


Ich werde ein paar Dinge hinzufügen, die ich in den anderen Antworten nicht erwähnt habe. (Zur Zeit schreibe ich das, das heißt die Antworten von Thierry, Günter und A_Singh).

  • Injectable() Sie den von Ihnen erstellten Diensten immer Injectable() . Obwohl es nur benötigt wird, wenn Ihr Dienst selbst etwas einschleusen muss, ist es eine bewährte Methode, es immer einzuschließen.
  • Das providers Array für Direktiven / Komponenten und das providers Array in NgModules sind die einzigen beiden Möglichkeiten, Anbieter zu registrieren, die nicht integriert sind. (Beispiele für eingebaute Objekte, die nicht registriert werden ElementRef , sind ElementRef , ApplicationRef usw. Diese können einfach ElementRef .)
  • Wenn eine Komponente über ein providers Array verfügt, erhält diese Komponente einen Angular-Injektor. Die Injektoren werden konsultiert, wenn eine Abhängigkeit (wie im Konstruktor angegeben) eingefügt werden soll. Ich stelle mir den Injektorbaum gerne als einen spärlicheren Baum als den Komponentenbaum vor. Der erste Injektor, der eine Abhängigkeitsanforderung erfüllen kann, tut dies. Diese Hierarchie von Injektoren ermöglicht es, dass Abhängigkeiten Singletons sind oder nicht.

Warum @Injectable ()?

@Injectable () markiert eine Klasse als verfügbar für einen Injektor zur Instanziierung. Im Allgemeinen meldet ein Injektor einen Fehler, wenn er versucht, eine Klasse zu instanziieren, die nicht als @Injectable () markiert ist.

Zufällig hätten wir @Injectable () in unserer ersten Version von HeroService weglassen können, da es keine injizierten Parameter hatte. Aber wir müssen es jetzt haben, da unser Service eine injizierte Abhängigkeit hat. Wir brauchen es, weil Angular Konstruktorparameter-Metadaten benötigt, um einen Logger zu injizieren.

EMPFEHLUNG: HINZUFÜGEN VON @INJECTABLE () ZU JEDER SERVICEKLASSE Wir empfehlen, @Injectable () zu jeder Serviceklasse hinzuzufügen, auch wenn diese keine Abhängigkeiten aufweist und daher technisch nicht erforderlich ist. Hier ist der Grund:

Zukunftssicherheit: Sie müssen sich nicht an @Injectable () erinnern, wenn Sie später eine Abhängigkeit hinzufügen.

Konsistenz: Alle Dienstleistungen folgen den gleichen Regeln, und wir müssen uns nicht wundern, warum ein Dekorateur fehlt.

Injektoren sind auch dafür verantwortlich, Komponenten wie HeroesComponent zu instanziieren. Warum haben wir HeroesComponent nicht als @Injectable () markiert?

Wir können es hinzufügen, wenn wir wirklich wollen. Dies ist nicht erforderlich, da die HeroesComponent bereits mit @Component markiert ist und diese Decorator-Klasse (wie @Directive und @Pipe, die wir später kennenlernen werden) ein Subtyp von InjectableMetadata ist. Tatsächlich identifizieren InjectableMetadata-Dekoratoren eine Klasse als Ziel für die Instanziierung durch einen Injektor.

Quelle: https://angular.io/docs/ts/latest/guide/dependency-injection.html







angular2-di