webentwicklung-frage-antwort-db.com.de

Wie man Abhängigkeitsinjektion (DI) korrekt in Angular2 verwendet?

Ich habe versucht herauszufinden, wie die (DI) Dependency Injection in Angular2 funktioniert. Jedes Mal, wenn ich versuchte, einen Dienst/eine Klasse in meine Komponenten einzuspritzen, stieß ich auf viele Probleme/Probleme. 

Aus verschiedenen gegoogelten Artikeln muss ich entweder providers: [] in der Komponentenkonfiguration verwenden, oder manchmal muss ich @Inject() in meinem Konstruktor verwenden oder direkt in bootstrap(app, [service]) injizieren. Ich habe auch gesehen, dass einige Artikel @injectable-Dekorateur haben sollen. 

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, wann was verwendet werden soll? Könnten Sie bitte ein Beispiel-Code-Snippet angeben? Vielen Dank :-)

24
George Huang

Die Abhängigkeitsinjektion in Angular2 basiert auf hierarchischen Injektoren, die mit der Baumstruktur der Komponenten verknüpft sind.

Das bedeutet, dass Sie Anbieter auf verschiedenen Ebenen konfigurieren können:

  • Für die gesamte Anwendung beim Bootstrapping. In diesem Fall sehen alle Sub-Injektoren (die Komponenten) diesen Anbieter und teilen sich die zugehörige Instanz. Bei der Interaktion handelt es sich um dieselbe Instanz
  • Für eine bestimmte Komponente und ihre Unterkomponenten. Gleich wie zuvor, jedoch für eine bestimmte Komponente. Andere Komponenten werden diesen Anbieter nicht sehen. Wenn Sie etwas definieren, das oben definiert wurde (z. B. beim Bootstrapping), wird stattdessen dieser Provider verwendet. So können Sie Dinge überschreiben.
  • Für Dienstleistungen. Es sind keine Anbieter mit ihnen verbunden. Sie verwenden Einspritzer des auslösenden Elements (direkt = Komponente oder indirekt = Komponente, die den Aufruf der Servicekette auslöst).

Zu Ihren anderen Fragen:

  • @Injektierbar. Um in eine Klasse zu injizieren, benötigen Sie einen Dekorateur. Komponenten haben eine (die @Component-Komponente), Dienste sind jedoch einfache Klassen. Wenn für einen Dienst Abhängigkeiten erforderlich sind, benötigen Sie diesen Dekorateur.
  • @Injizieren. In den meisten Fällen reicht der Typ der Konstruktorparameter aus, um Angular2 bestimmen zu lassen, was injiziert werden soll. In einigen Fällen (wenn Sie beispielsweise explizit ein OpaqueToken und keine Klasse zum Registrieren von Providern verwenden), müssen Sie einige Hinweise dazu angeben, was eingefügt werden soll. In solchen Fällen müssen Sie @Inject verwenden.

Siehe diese Fragen für weitere Details:

13

Breite Frage, TL; DR Version


@ Injectable ()

  • ist ein Dekorateur, der der TypeScript mitteilt, dass die dekorierte Klasse dependencies hat 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, [Service])

  • 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 bootstrap Ihre Anwendung mit den Diensten, die an vielen Orten wie Http verwendet werden, was auch bedeutet, dass Sie nicht providers: [Http] In Ihre Anwendung schreiben müssen Klassenkonfiguration.

Anbieter: [Dienst]

  • die Anbieter übernehmen auch die Aufgabe, alle Argumente der Dienste an Injector zu übergeben.

  • Sie legen Dienste in Providern ab, wenn sie nicht mit bootstrap() pedieren. Und wird nur an wenigen Stellen benötigt.

@ Inject ()

  • ist auch ein Dekorateur Eine Funktion, die die Arbeit des tatsächlichen Injizierens dieser Dienste übernimmt
    so was. constructor(@Inject(NameService) nameService)
  • wenn Sie jedoch TS verwenden, müssen Sie nur diese constructor(nameService: NameService) ausführen. Den Rest erledigt TypeScript.

Weitere Lektüre

Hoffe das hilft. :)

17
Ankit Singh

Ich muss entweder Anbieter verwenden: [] 

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

Bei der Registrierung eines Providers bestimmt der Umfang des erstellten Wertes . Angulars DI ist hierarchisch.
Wenn Sie einen Anbieter im Stammverzeichnis der Baumstruktur 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]) (Wurzelkomponente) 


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 (über einen Konstruktorparameter) anfordert, blickt DI in der Komponentenstruktur (beginnend mit leaf zum Stamm) nach oben und nimmt den ersten gefundenen Provider. Wenn bereits eine Instanz für diesen Anbieter erstellt wurde, wird diese Instanz verwendet. Andernfalls wird eine neue Instanz erstellt.

@Injizieren()

Wenn eine Komponente oder ein Dienst einen Wert von DI anfordert, z

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() übergebenen Parameters. Im obigen Beispiel ist der an @Inject() übergebene Parameter derselbe wie der Parametertyp. Daher ist @Inject(SomeType) redundant.

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

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

Der Typ string reicht nicht aus, um eine bestimmte Konfigurationseinstellung zu unterscheiden, wenn Sie mehrere registriert haben.
.__ Der Konfigurationswert muss an einem beliebigen Ort als Provider registriert werden


> = RC.5

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

<= RC.4

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

Daher brauchen Sie @Inject() nicht für FormBuilder, wenn der Konstruktor aussieht

constructor(formBuilder: FormBuilder) {}
4

Ich werde ein paar Dinge hinzufügen, die ich in den anderen Antworten nicht erwähnt habe. (Zum Zeitpunkt, als ich dies schreibe, sind dies die Antworten von Thierry, Günter und A_Singh).

  • Fügen Sie den von Ihnen erstellten Diensten immer Injectable() hinzu. Obwohl dies nur erforderlich ist, wenn Ihr Dienst selbst etwas injizieren muss, ist es eine bewährte Methode, dies immer einzuschließen.
  • Das providers-Array in directives/components und das providers-Array in NgModules sind die einzigen zwei Möglichkeiten, nicht integrierte Provider zu registrieren. (Beispiele für eingebaute Objekte, die wir nicht registrieren müssen, sind ElementRef, ApplicationRef usw. Wir können diese einfach einfügen.)
  • Wenn eine Komponente ein providers-Array hat, erhält diese Komponente einen Angular-Injektor. Die Injektoren werden konsultiert, wenn etwas (wie im Konstruktor angegeben) eine Abhängigkeit injizieren möchte. Ich stelle mir den Injektorbaum als einen spärlicheren Baum vor als den Komponentenbaum. 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.
2
Mark Rajcok

Warum @Injectable ()?

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

Zufällig hätten wir @Injectable () aus unserer ersten Version von HeroService weglassen können, da es keine eingepflegten Parameter gab. Aber wir müssen jetzt wissen, dass unser Dienst eine Abhängigkeit hat. Wir brauchen es, weil Angular Konstruktorparameter-Metadaten benötigt, um einen Logger einzufügen.

VORSCHLAG: ADDIEREN SIE @INJECTABLE () ZU JEDER SERVICEKLASSE Wir empfehlen, jeder Serviceklasse @Injectable () hinzuzufügen, auch wenn diese keine Abhängigkeiten haben und dies daher technisch nicht erforderlich ist. Hier ist der Grund:

Zukünftiges Proofing: Wenn Sie später eine Abhängigkeit hinzufügen, müssen Sie sich nicht an @Injectable () erinnern.

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

Injektoren sind auch für das Instanziieren von Komponenten wie HeroesComponent verantwortlich. 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 Dekoratorklasse (wie @Directive und @Pipe, über die wir später noch etwas erfahren werden) ein Subtyp von InjectableMetadata ist. InjectableMetadata-Dekorateure identifizieren eine Klasse als Ziel für die Instantiierung durch einen Injektor.

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

0
stackdave