providedInオプションを使うべき?使わないべき?
Angular 6におけるInjectableデコレータのprovidedInオプションの目的
providedIn
オプションは、サービスのインスタンスをどこで生成するかを指定します。以下の3つの値を設定できます。
root
: サービスはルートインジェクタで生成され、アプリケーション全体でシングルトンとして提供されます。any
: サービスはコンポーネント、ディレクティブ、サービスなど、どこからでも注入できます。custom
: サービスはカスタムのインジェクタで生成されます。
providedInオプションの使用例
サービスをルートインジェクタで生成する
@Injectable({
providedIn: 'root'
})
export class MyService {
// ...
}
上記のコードでは、MyService
はルートインジェクタで生成されます。つまり、アプリケーション全体でMyService
の唯一のインスタンスが作成され、すべてのコンポーネントやサービスから注入できます。
サービスをコンポーネントで生成する
@Component({
selector: 'my-component',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.css']
})
export class MyComponent {
constructor(private readonly myService: MyService) {
// ...
}
}
@Injectable({
providedIn: MyComponent
})
export class MyService {
// ...
}
上記のコードでは、MyService
はMyComponent
コンポーネントで生成されます。つまり、MyComponent
コンポーネントのインスタンスごとにMyService
の新しいインスタンスが作成されます。
サービスをカスタムインジェクタで生成する
import { Injectable } from '@angular/core';
@Injectable()
export class MyCustomInjector {
// ...
}
@Injectable({
providedIn: MyCustomInjector
})
export class MyService {
// ...
}
上記のコードでは、MyService
はMyCustomInjector
カスタムインジェクタで生成されます。
- サービスの依存関係注入をより細かく制御できる
- サービスのライフサイクルをより明確に定義できる
- コードのテストがしやすくなる
providedInオプションを使用するデメリット
- コードの複雑さが増す
- 誤った設定により、予期せぬ動作が発生する可能性がある
providedIn
オプションは、Angular 6におけるサービスの生成と依存関係注入を制御するための強力なツールです。オプションの役割と使用例を理解し、適切な設定を行うことで、コードの品質とパフォーマンスを向上させることができます。
サービスをルートインジェクタで生成する
// my-service.ts
@Injectable({
providedIn: 'root'
})
export class MyService {
constructor() {
console.log('MyService created!');
}
doSomething() {
console.log('MyService doing something!');
}
}
// my-component.ts
@Component({
selector: 'my-component',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.css']
})
export class MyComponent {
constructor(private readonly myService: MyService) {
console.log('MyComponent created!');
this.myService.doSomething();
}
}
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { MyComponent } from './my-component/my-component.component';
@NgModule({
declarations: [
AppComponent,
MyComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
MyService created!
MyComponent created!
MyService doing something!
サービスをコンポーネントで生成する
// my-service.ts
@Injectable({
providedIn: MyComponent
})
export class MyService {
constructor() {
console.log('MyService created!');
}
doSomething() {
console.log('MyService doing something!');
}
}
// my-component.ts
@Component({
selector: 'my-component',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.css']
})
export class MyComponent {
constructor(private readonly myService: MyService) {
console.log('MyComponent created!');
this.myService.doSomething();
}
}
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { MyComponent } from './my-component/my-component.component';
@NgModule({
declarations: [
AppComponent,
MyComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
上記のコードを実行すると、コンソールに以下の出力が出力されます。
MyService created!
MyComponent created!
MyService created!
MyService doing something!
サービスをカスタムインジェクタで生成する
// my-custom-injector.ts
import { Injectable } from '@angular/core';
@Injectable()
export class MyCustomInjector {
constructor() {
console.log('MyCustomInjector created!');
}
get(token: any) {
if (token === MyService) {
return new MyService();
}
return null;
}
}
// my-service.ts
@Injectable({
providedIn: MyCustomInjector
})
export class MyService {
constructor() {
console.log('MyService created!');
}
doSomething() {
console.log('MyService doing something!');
}
}
// my-component.ts
@Component({
selector: 'my-component',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.css']
})
export class MyComponent {
constructor(private readonly myService: MyService) {
console.log('MyComponent created!');
this.myService.doSomething();
}
}
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { MyComponent } from './my-component/my-component.component';
@NgModule({
declarations: [
AppComponent,
MyComponent
],
imports: [
BrowserModule
],
providers: [
MyCustomInjector
],
bootstrap
サービスの生成方法
コンストラクタインジェクション
コンポーネントまたは他のサービスのコンストラクタでサービスを直接注入できます。
// my-service.ts
export class MyService {
constructor() {
console.log('MyService created!');
}
doSomething() {
console.log('MyService doing something!');
}
}
// my-component.ts
@Component({
selector: 'my-component',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.css']
})
export class MyComponent {
constructor(private readonly myService: MyService) {
console.log('MyComponent created!');
this.myService.doSomething();
}
}
サービスファクトリーを使用してサービスを生成できます。
// my-service-factory.ts
import { Injectable } from '@angular/core';
@Injectable()
export class MyServiceFactory {
constructor() {
console.log('MyServiceFactory created!');
}
create() {
return new MyService();
}
}
// my-service.ts
export class MyService {
constructor() {
console.log('MyService created!');
}
doSomething() {
console.log('MyService doing something!');
}
}
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { MyComponent } from './my-component/my-component.component';
@NgModule({
declarations: [
AppComponent,
MyComponent
],
imports: [
BrowserModule
],
providers: [
MyServiceFactory,
{
provide: MyService,
useFactory: (myServiceFactory: MyServiceFactory) => myServiceFactory.create()
}
],
bootstrap: [AppComponent]
})
export class AppModule { }
NgModule
のproviders
プロパティを使用してサービスを生成できます。
// my-service.ts
export class MyService {
constructor() {
console.log('MyService created!');
}
doSomething() {
console.log('MyService doing something!');
}
}
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { MyComponent } from './my-component/my-component.component';
@NgModule({
declarations: [
AppComponent,
MyComponent
],
imports: [
BrowserModule
],
providers: [
MyService
],
bootstrap: [AppComponent]
})
export class AppModule { }
// my-service-locator.ts
import { Injectable } from '@angular/core';
@Injectable()
export class MyServiceLocator {
private readonly services = new Map<any, any>();
constructor() {
console.log('MyServiceLocator created!');
}
get(token: any) {
if (!this.services.has(token)) {
this.services.set(token, new token());
}
return this.services.get(token);
}
}
// my-service.ts
export class MyService {
constructor() {
console.log('MyService created!');
}
doSomething() {
console.log('MyService doing something!');
}
}
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { MyComponent } from './my-component/my-component.component';
@NgModule({
declarations: [
AppComponent,
MyComponent
],
imports: [
BrowserModule
],
providers: [
MyServiceLocator,
{
provide: MyService,
useFactory: (myServiceLocator: MyServiceLocator) => my
angular typescript angular6