问题
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?
回答1:
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.
回答2:
Does a service that is provided in "root" within the @Injectable() decorator still have to be in the providers array of the module?
No!
When you create a service with the Angular CLI I believe that the providedIn: "root"
is added by default, so technically you do not ever need to add one of your own services into a providers array.
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?
It should be enough that it is provided at the root level using the decorator.
However, not all of the services I create are intended to be global. It is not uncommon for me to remove the configuration object to the @Injectable()
metadata when I am creating a service that will be shared among a single screen or sub module--not across the full application.In such a case I will have to add that service to a providers array on the respective components that use it or sub module declaration.
来源:https://stackoverflow.com/questions/60377330/injectable-decorator-and-providers-array