@Injectable() 装饰器和提供者数组 [英] @Injectable() decorator and providers array

查看:55
本文介绍了@Injectable() 装饰器和提供者数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在@Injectable() 装饰器中的root"中提供的服务是否仍然必须在模块的 providers 数组中?

Angular 文档 并没有真正给我答案,或者我不太清楚明白了.

在我的核心文件夹中,我有一个以 root 身份提供的身份验证服务.我不想在 app 模块中导入我的核心模块,以便使用提供的所有服务和组件.

我是否必须在模块的 providers 数组中额外设置服务,还是已经使用装饰器在根级别提供服务就足够了?

解决方案

您提供的链接中的要点是注册服务的所有不同方法,从最不具体到最具体.

特定于应用程序 - 使用 @Injectable({ providedIn: 'root' })

<块引用>

当您在根级别提供服务时,Angular 会创建一个单一的 HeroService 共享实例,并将其注入到任何需要它的类中.在 @Injectable() 元数据中注册提供者还允许 Angular 通过从未使用的已编译应用程序中删除服务来优化应用程序.

特定于模块 - 在模块提供程序中注册

<块引用>

当您向特定 NgModule 注册提供者时,该 NgModule 中的所有组件都可以使用相同的服务实例.要在此级别注册,请使用 @NgModule() 装饰器的 providers 属性,

组件特​​定 - 在组件中注册

<块引用>

当您在组件级别注册提供者时,您将获得该服务的新实例以及该组件的每个新实例.在组件级别,在@Component() 元数据的 providers 属性中注册一个服务提供者.

以上所有引用均来自官方服务和依赖注入介绍页面

  • 如果你只有一个模块,那么前两种方法是等价的,只需要使用一种方法.使用 @Injectable - 默认的 CLI 方法更容易.
  • 如果要在多个模块之间共享服务实例,请使用第一种方法.
  • 如果您希望每个独立模块有一个实例,请使用第二种方法.
  • 如果您想与除一个组件之外的所有组件共享一个应用程序范围的实例,那么除了对一个异常组件使用第三种方法之外,还可以使用第一种方法.

我认为大多数用例都属于前两种方法.

注册特定于模块的服务

提示:只需使用 providedIn: 'root'.如果由于树抖动而未使用模块,则不会为模块编译未使用的服务.声明特定于模块的服务似乎是多余的,而且正如我们将看到的,可能会导致问题.

有两种方法可以注册特定于模块的服务 - 从模块或从服务.

模块

@NgModule({提供者:[MyService]})导出类 MyModule {}

服务

@Injectable({ providedIn: MyModule })

后者是官方推荐的方法.声明 providers 数组是早期的遗留问题.

来自文档:

<块引用>

上面的示例显示了在模块中提供服务的首选方式.这种方法是首选,因为如果没有注入它,它会启用服务的摇树.如果无法在服务中指定应该由哪个模块提供,您也可以在模块内为服务声明一个提供者

为什么你应该只使用 providedIn: 'root'

所以我们看到这种方法是可摇树的.到现在为止还挺好.但是,如果您只是尝试导入声明使用客户端的组件所在的相同模块,您最终会得到循环引用.

进行此设置:

我的模块

 声明:[我的组件]

我的服务

@Injectable({ providedIn: MyModule })

我的组件

constructor(private myService: MyService) {}

  • my-service 导入 my-module
  • my-module 导入 my-component
  • my-component 导入 my-service

存在循环依赖.

解决方法是创建一个服务模块并将其导入您的模块.

我的模块

导入:[我的模块服务],声明: [我的组件]

我的模块服务

<预><代码>

我的服务

@Injectable({ providedIn: MyModuleServices })

我的组件

constructor(private myService: MyService) {}

这是一个非常冗长的替代方法,可以简单地使用 providedIn: 'root' 并让树摇动来完成工作.

Does a service that is provided in "root" within the @Injectable() decorator still have to be in the providers array of the module?

The Angular documentation doesn't really give me an answer or I don't quite understand it.

Inside my core folder I have a authentication service which is provided in root. I wan't to import my core module inside the app module in order to use all the services and components provided.

Do I have to additionally set up the service in the providers array of the module, or is it enough that it is already provided at root level using the decorator?

解决方案

The bullet points in the link you provided are all different methods of registering services, from the least specific to most specific.

App-specific - use @Injectable({ providedIn: 'root' })

When you provide the service at the root level, Angular creates a single, shared instance of HeroService and injects it into any class that asks for it. Registering the provider in the @Injectable() metadata also allows Angular to optimize an app by removing the service from the compiled app if it isn't used.

Module-specific - register in module providers

When you register a provider with a specific NgModule, the same instance of a service is available to all components in that NgModule. To register at this level, use the providers property of the @NgModule() decorator,

Component-specific - register in component

When you register a provider at the component level, you get a new instance of the service with each new instance of that component. At the component level, register a service provider in the providers property of the @Component() metadata.

All quotes above are from the official Introduction to services and dependency injection page

  • If you only have one module, then the first two methods are equivalent and only need to use one method. It's easier to go with @Injectable - the default CLI approach.
  • If you want to share service instances between multiple modules, use the first method.
  • If you want one instance per independent module, use the second approach.
  • If you want to share an app-wide instance with all components except one, then use the first approach in addition to the third approach for the one anomalous component.

It is my opinion that most use cases would fall into the first two approaches.

Registering module-specific services

Tip: just use providedIn: 'root'. Unused services won't be compiled for a module if it isn't used due to tree shaking. Declaring module-specific services seems redundant and, as we shall see, can cause problems.

There are two ways to register module-specific services - either from the module or from the service.

module

@NgModule({
  providers: [MyService]
})
export class MyModule {}

service

@Injectable({ providedIn: MyModule })

The latter is the officially recommended approach. Declaring the providers array is a hangover from the earlier days.

From the docs:

The example above shows the preferred way to provide a service in a module. This method is preferred because it enables tree-shaking of the service if nothing injects it. If it's not possible to specify in the service which module should provide it, you can also declare a provider for the service within the module

Why you should just use providedIn: 'root'

So we see that this approach is tree-shakeable. So far so good. But you will end up with circular references if you simply try to import the same module that the components consuming the clients are declared in.

Take this setup:

my-module

declarations: [
  MyComponent
]

my-service

@Injectable({ providedIn: MyModule })

my-component

constructor(private myService: MyService) {}

  • my-service imports my-module
  • my-module imports my-component
  • my-component imports my-service

There is a circular dependency.

The workaround for this is to create a service module and import that into your module.

my-module

imports: [
  MyModuleServices
],
declarations: [
  MyComponent
]

my-module-services


my-service

@Injectable({ providedIn: MyModuleServices })

my-component

constructor(private myService: MyService) {}

This is a very long-winded alternative to simply using providedIn: 'root' and letting the tree shaking do the work.

这篇关于@Injectable() 装饰器和提供者数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆