我一直试图弄清楚(DI)依赖注入如何在Angular2中工作。每当我尝试将服务/或类注入到我的组件中时,我遇到了很多问题/问题。
从不同的谷歌文章中,我需要在组件配置中使用providers: []
,或者有时我需要在构造函数中使用@Inject()
或直接在bootstrap(app, [service])
中注入?我也看到一些文章要我放@injectable
装饰。
例如:要注入Http,我只需要import{Http}
并将Http放在提供程序中,但对于FormBuilder,我需要在构造函数中使用@Inject()
。
什么时候使用什么有什么经验法则?你能提供一些示例代码片段吗?谢谢: - )
答案 0 :(得分:17)
广泛的问题, TL; DR 版本
<强> @Injectable() 强>
是一个装饰器,告诉sudo su -
gedit ~/.bashrc
export PATH=${PATH}:/your path
export PATH=${PATH}:/your path
export PATH=${PATH}:/opt/workspace/android/android-sdk-linux/tools
export PATH=${PATH}:/opt/workspace/android/android-sdk-linux/platform-tools
装饰类有typescript
,并不意味着这个类可以注入其他类。
然后TypeScript了解它需要在构造时使用dependencies
依赖项将所需元数据注入到修饰类中。
<强> bootstrap(app, [service]) 强>
bootstrap()负责在我们的应用程序引导时为其创建根注入器。它将提供者列表作为第二个参数,在创建时将直接传递给注入器。
您使用将在imported
等许多地方使用的服务来引导您的应用程序,这也意味着您不需要在类配置中编写Http
。
<强> providers: [service] 强>
提供商还负责将所有服务的参数传递给providers: [Http]
。
如果服务提供商不是Injector
,则将服务提供给服务提供商。并且仅在少数地方需要。
<强> @Inject() 强>
bootstrap()
constructor(@Inject(NameService) nameService)
并且打字稿将处理其余部分。进一步阅读
如果您想深入了解 DI ,请查看this amazing article
希望这会有所帮助。 :)
答案 1 :(得分:13)
Angular2中的依赖注入依赖于链接到组件树的分层注入器。
这意味着您可以在不同级别配置提供商:
关于您的其他问题:
有关其他详细信息,请参阅以下问题:
答案 2 :(得分:4)
我需要使用提供者:[]
要使依赖注入能够为您创建实例,您需要为这些类(或其他值)注册提供者某处。
注册提供者的位置决定了创建值的范围。
Angulars DI是分层的。
如果您在树的根目录注册提供程序
<强>&GT; = RC.5 强>
@NgModule({
providers: [/*providers*/]
...
})
或延迟加载的模块
static forRoot(config: UserServiceConfig): ModuleWithProviders {
return {
ngModule: CoreModule,
providers: [
{provide: UserServiceConfig, useValue: config }
]
};
}
<强>&LT = RC.4 强>
(bootstrap(AppComponent, [Providers})
或@Component(selector: 'app-component', providers: [Providers])
(根组件)
然后请求实例的所有组件和服务都获得相同的实例。
如果提供者在其中一个子组件中注册,则为该组件的后代提供新的(不同的)实例。
如果一个组件请求一个实例(通过构造函数参数),DI看起来“向上”组件树(从leaf开始向根),并获取它找到的第一个提供者。如果先前已创建此提供程序的实例,则使用此实例,否则将创建新实例。
@注入()
当组件或服务从DI请求值
时constructor(someField:SomeType) {}
DI按类型SomeType
查找提供商。如果添加了@Inject(SomeType)
constructor(@Inject(SomeType) someField:SomeType) {}
DI通过传递给@Inject()
的参数查找提供程序。在上面的示例中,传递给@Inject()
的参数与参数的类型相同,因此@Inject(SomeType)
是多余的。
但是,在某些情况下,您需要自定义行为,例如注入配置设置。
constructor(@Inject('someName') someField:string) {}
当您注册多个时,类型string
不足以区分特定的配置设置
配置值需要在某个地方注册为提供者,如
<强>&GT; = RC.5 强>
@NgModule({
providers: [{provide: 'someName', useValue: 'abcdefg'})]
...
})
export class AppModule {}
<强>&LT = RC.4 强>
bootstrap(AppComponent, [provide('someName', {useValue: 'abcdefg'})])
因此,如果构造函数看起来像<{1}},则@Inject()
不需要FormBuilder
constructor(formBuilder: FormBuilder) {}
答案 3 :(得分:2)
我会在其他答案中添加一些我没有看到的内容。 (在我写这篇文章时,这意味着来自Thierry,Günter和A_Singh的答案)。
Injectable()
添加到您创建的服务中。虽然只有在您的服务本身需要注入某些内容时才需要它,但最好始终包含它。providers
数组和NgModules中的providers
数组是注册非内置提供程序的唯一两种方法。 (我们不需要注册的内置对象示例包括ElementRef
,ApplicationRef
等。我们可以简单地注入这些对象。)providers
数组时,该组件将获得Angular注入器。当某些东西想要注入依赖项时(参见构造函数中的指定),会查询注入器。我喜欢将注入器树视为比组件树更好的树。能够满足依赖性请求的第一个注入器就是这样做的。这种注入器层次结构允许依赖关系是单例还是非单例。答案 4 :(得分:0)
为什么选择@Injectable()?
@Injectable()将一个类标记为可用于实例化的注入器。一般来说,当尝试实例化未标记为@Injectable()的类时,注入器将报告错误。
实际上,我们可能已经从我们的第一个HeroService版本中省略了@Injectable(),因为它没有注入参数。但是我们必须拥有它,因为我们的服务具有注入依赖性。我们需要它,因为Angular需要构造函数参数元数据才能注入Logger。
建议:将@INJECTABLE()添加到每个服务类别 我们建议将@Injectable()添加到每个服务类中,即使是那些没有依赖项的服务类,因此在技术上也不需要它。这就是原因:
面向未来:当我们稍后添加依赖项时,无需记住@Injectable()。
一致性:所有服务都遵循相同的规则,我们不必怀疑为什么缺少装饰器。
Injectors还负责实例化HeroesComponent之类的组件。为什么我们没有将HeroesComponent标记为@Injectable()?
如果我们真的想要,我们可以添加它。这是不必要的,因为HeroesComponent已经用@Component标记,并且这个装饰类(如@Directive和@Pipe,我们稍后会了解)是InjectableMetadata的子类型。它实际上是InjectableMetadata装饰器,它将类标识为注入器实例化的目标。
来源:https://angular.io/docs/ts/latest/guide/dependency-injection.html