injection - ¿Cómo utilizar la inyección de dependencia(DI) correctamente en Angular2?
inyeccion de dependencias angular 4 (5)
He estado tratando de descubrir cómo funciona la inyección de dependencia (DI) en Angular2. Me encontré con muchos problemas / problemas cada vez que intenté inyectar un servicio / clase en mis componentes.
De diferentes artículos en Google, necesito usar
providers: []
en la configuración de Componente, o algunas veces necesito usar
@Inject()
en mi constructor o inyectar directamente en el
bootstrap(app, [service])
.
También he visto que algunos artículos quieren que ponga decorador
@injectable
.
Por ejemplo: para inyectar Http, solo necesito
import{Http}
y poner Http en los proveedores, pero para FormBuilder, necesito usar
@Inject()
en el constructor.
¿Hay alguna regla general sobre cuándo usar qué? ¿Podría proporcionar algún fragmento de código de ejemplo? Gracias :-)
Necesito usar proveedores: []
Para que la inyección de dependencia pueda crear instancias para usted, debe registrar proveedores para estas clases (u otros valores) en alguna parte .
Cuando registra un proveedor determina el alcance del valor creado.
Angulares DI es jerárquico.
Si registra un proveedor en la raíz del árbol
> = RC.5
@NgModule({
providers: [/*providers*/]
...
})
o para módulos con carga lenta
static forRoot(config: UserServiceConfig): ModuleWithProviders {
return {
ngModule: CoreModule,
providers: [
{provide: UserServiceConfig, useValue: config }
]
};
}
<= RC.4
(
bootstrap(AppComponent, [Providers})
o
@Component(selector: ''app-component'', providers: [Providers])
(componente raíz)
entonces todos los componentes y servicios que solicitan una instancia obtienen la misma instancia.
Si un proveedor está registrado en uno de los componentes secundarios, se proporciona una nueva instancia (diferente) para los descendientes de este componente.
Si un componente solicita una instancia (mediante un parámetro de constructor), DI mira "hacia arriba" el árbol de componentes (comenzando desde la hoja hacia la raíz) y toma el primer proveedor que encuentra. Si una instancia para este proveedor ya se creó anteriormente, se utiliza esta instancia; de lo contrario, se crea una nueva instancia.
@Inyectar()
Cuando un componente o servicio solicita un valor de DI como
constructor(someField:SomeType) {}
DI busca al proveedor por el tipo
SomeType
.
Si se
@Inject(SomeType)
constructor(@Inject(SomeType) someField:SomeType) {}
DI busca al proveedor por el parámetro pasado a
@Inject()
.
En el ejemplo anterior, el parámetro pasado a
@Inject()
es el mismo que el tipo del parámetro, por
@Inject(SomeType)
tanto,
@Inject(SomeType)
es redundante.
Sin embargo, hay situaciones en las que desea personalizar el comportamiento, por ejemplo, para inyectar una configuración.
constructor(@Inject(''someName'') someField:string) {}
La
string
tipo no es suficiente para distinguir una configuración específica cuando tiene varios registrados.
El valor de configuración debe registrarse como proveedor en algún lugar como
> = RC.5
@NgModule({
providers: [{provide: ''someName'', useValue: ''abcdefg''})]
...
})
export class AppModule {}
<= RC.4
bootstrap(AppComponent, [provide(''someName'', {useValue: ''abcdefg''})])
Por lo tanto, no necesita
@Inject()
para
FormBuilder
si el constructor se parece a
constructor(formBuilder: FormBuilder) {}
¿Por qué @Injectable ()?
@Injectable () marca una clase como disponible para un inyector para instanciación. En términos generales, un inyector informará un error cuando intente crear una instancia de una clase que no esté marcada como @Injectable ().
Como sucede, podríamos haber omitido @Injectable () de nuestra primera versión de HeroService porque no tenía parámetros inyectados. Pero debemos tenerlo ahora que nuestro servicio tiene una dependencia inyectada. Lo necesitamos porque Angular requiere metadatos de parámetros de constructor para inyectar un registrador.
SUGERENCIA: AGREGAR @INJECTABLE () A CADA CLASE DE SERVICIO Recomendamos agregar @Injectable () a cada clase de servicio, incluso aquellos que no tienen dependencias y, por lo tanto, técnicamente no lo requieren. Este es el por qué:
Pruebas futuras: no es necesario recordar @Injectable () cuando agreguemos una dependencia más adelante.
Consistencia: todos los servicios siguen las mismas reglas, y no tenemos que preguntarnos por qué falta un decorador.
Los inyectores también son responsables de crear instancias de componentes como HeroesComponent. ¿Por qué no hemos marcado HeroesComponent como @Injectable ()?
Podemos agregarlo si realmente queremos. No es necesario porque HeroesComponent ya está marcado con @Component, y esta clase de decorador (como @Directive y @Pipe, que veremos más adelante) es un subtipo de InjectableMetadata. De hecho, los decoradores de InyectableMetadata son los que identifican una clase como objetivo para la creación de instancias por parte de un inyector.
Fuente: https://angular.io/docs/ts/latest/guide/dependency-injection.html
Agregaré algunas cosas que no vi mencionadas en las otras respuestas. (En el momento en que escribo esto, eso significa las respuestas de Thierry, Günter y A_Singh).
-
Agregue siempre
Injectable()
a los servicios que cree. Aunque solo es necesario si su propio servicio necesita inyectar algo, es una buena práctica incluirlo siempre. -
La matriz de
providers
en directivas / componentes y la matriz deproviders
en NgModules son las únicas dos formas de registrar proveedores que no están integrados. (Los ejemplos de objetos integrados que no tenemos que registrar sonElementRef
,ApplicationRef
, etc. Simplemente podemos inyectarlos). -
Cuando un componente tiene una matriz de
providers
, ese componente obtiene un inyector angular. Los inyectores son consultados cuando algo quiere inyectar una dependencia (como se especifica en el constructor). Me gusta pensar en el árbol del inyector como un árbol más libre que el árbol componente. El primer inyector que puede satisfacer una solicitud de dependencia lo hace. Esta jerarquía de inyectores permite que las dependencias sean simples o no.
La inyección de dependencia en Angular2 se basa en inyectores jerárquicos que están vinculados al árbol de componentes.
Esto significa que puede configurar proveedores en diferentes niveles:
- Para toda la aplicación al arrancarlo. En estos casos, todos los subinyectores (los componentes) verán a este proveedor y compartirán la instancia asociada. Al interactuar, será la misma instancia
- Para un componente específico y sus subcomponentes. Igual que antes pero para un componente específico. Otros componentes no verán a este proveedor. Si redefine algo definido anteriormente (por ejemplo, con bootstrapping), este proveedor se utilizará en su lugar. Entonces puedes anular las cosas.
- Por servicios. No hay proveedores asociados con ellos. Usan unos del inyector del elemento que dispara (directamente = un componente o indirectamente = un componente que dispara la cadena de llamada de servicio)
Con respecto a sus otras preguntas:
- @Inyectable. Para inyectar en una clase, necesitas un decorador. Los componentes tienen uno (@Component one) pero los servicios son clases simples. Si un servicio requiere que se le inyecten dependencias, necesita este decorador.
- @Inyectar. En la mayoría de los casos, el tipo de parámetros del constructor es suficiente para que Angular2 determine qué inyectar. En algunos casos (por ejemplo, si utiliza explícitamente un OpaqueToken y no una clase para registrar proveedores), debe especificar algunos consejos sobre qué inyectar. En tales casos, debe usar @Inject.
Consulte estas preguntas para obtener detalles adicionales:
Pregunta amplia, TL; versión DR
-
es un decorador que le dice al
typescript
que la clase decorada tienedependencies
y no significa que esta clase pueda inyectarse en otra. -
Y luego TypeScript comprende que necesita inyectar los metadatos requeridos en la clase decorada al construir, utilizando las dependencias
imported
.
bootstrap (aplicación, [servicio])
-
bootstrap () se encarga de crear un inyector raíz para nuestra aplicación cuando es bootstrapped. Toma una lista de proveedores como segundo argumento que se pasará directamente al inyector cuando se cree.
-
Arranca su aplicación con los servicios que se utilizarán en muchos lugares como
Http
, lo que también significa que no necesitará escribirproviders: [Http]
en la configuración de su clase.
-
los proveedores también hacen el trabajo de pasar todos los argumentos de los servicios a
Injector
. -
Pones servicios en proveedores si no es
bootstrap()
ped con. Y solo se necesita en unos pocos lugares.
-
tambiénesun decorador,una función que hace el trabajo de inyectar esos servicios
Me gusta esto.constructor(@Inject(NameService) nameService)
-
pero si usa TS, todo lo que necesita hacer es este
constructor(nameService: NameService)
y el mecanografiado se encargará del resto.
Otras lecturas
-
Si desea profundizar en DI , eche un vistazo a este increíble artículo
-
y para entender Decoradores vs Anotaciones, vean esto .
-
Gunter''s Answer
Mark Rajcok''s Answer
yAccepted Answer
Espero que esto ayude. :)