RxJS の Subject を使って Angular サービスでデータやイベントを伝達する方法
Angular2 サービスにおける EventEmitter の適切な使用方法
EventEmitter の概要
- コンポーネント間でデータやイベントを伝達するためのクラス
- テンプレート内でイベントバインディングを使って購読
- サービス内で使用可能
サービスでの EventEmitter の使い方
誤った使い方
// サービスファイル
export class MyService {
someChange = new EventEmitter<SomeObject>();
// ...
}
// コンポーネントファイル
import { MyService } from './my.service';
constructor(private myService: MyService) {}
ngOnInit() {
this.myService.someChange.subscribe(obj => {
// データを受け取る
});
}
上記のように、サービス内で EventEmitter
を直接インスタンス化して使用することは 誤り です。
正しい使い方
RxJS の Subject を使う
// サービスファイル
import { Subject } from 'rxjs';
export class MyService {
private someChangeSubject = new Subject<SomeObject>();
someChange$ = this.someChangeSubject.asObservable();
// ...
emitSomeChange(obj: SomeObject) {
this.someChangeSubject.next(obj);
}
}
// コンポーネントファイル
import { MyService } from './my.service';
constructor(private myService: MyService) {}
ngOnInit() {
this.myService.someChange$.subscribe(obj => {
// データを受け取る
});
}
EventEmitter
は Subject
を継承しているので、代わりに Subject
を直接使用できます。
Observable を使う
// サービスファイル
export class MyService {
getSomeChange(): Observable<SomeObject> {
// ... データを取得する処理 ...
}
}
// コンポーネントファイル
import { MyService } from './my.service';
constructor(private myService: MyService) {}
ngOnInit() {
this.myService.getSomeChange().subscribe(obj => {
// データを受け取る
});
}
EventEmitter
や Subject
を使わず、直接 Observable
を返すことも可能です。
まとめ
サービス内で EventEmitter
を使う場合は、Subject
や Observable
を使って RxJS の機能を活用 するのが適切です。
関連用語
- Angular
- サービス
- コンポーネント
- Subject
- RxJS
サービスにおける EventEmitter のサンプルコード
誤った使い方
// サービスファイル
export class MyService {
someChange = new EventEmitter<SomeObject>();
constructor(private http: HttpClient) {}
getData() {
this.http.get('https://example.com/api/data').subscribe(data => {
this.someChange.emit(data);
});
}
}
// コンポーネントファイル
import { MyService } from './my.service';
constructor(private myService: MyService) {}
ngOnInit() {
this.myService.someChange.subscribe(obj => {
// データを受け取る
});
this.myService.getData();
}
- サービス内で直接
EventEmitter
をインスタンス化している - コンポーネントがサービスの内部処理に依存している
正しい使い方
// サービスファイル
import { Subject } from 'rxjs';
export class MyService {
private someChangeSubject = new Subject<SomeObject>();
someChange$ = this.someChangeSubject.asObservable();
constructor(private http: HttpClient) {}
getData() {
this.http.get('https://example.com/api/data').subscribe(data => {
this.someChangeSubject.next(data);
});
}
}
// コンポーネントファイル
import { MyService } from './my.service';
constructor(private myService: MyService) {}
ngOnInit() {
this.myService.someChange$.subscribe(obj => {
// データを受け取る
});
this.myService.getData();
}
改善点:
Subject
を使ってEventEmitter
をカプセル化
// サービスファイル
export class MyService {
constructor(private http: HttpClient) {}
getSomeChange(): Observable<SomeObject> {
return this.http.get('https://example.com/api/data');
}
}
// コンポーネントファイル
import { MyService } from './my.service';
constructor(private myService: MyService) {}
ngOnInit() {
this.myService.getSomeChange().subscribe(obj => {
// データを受け取る
});
}
- 上記はあくまでサンプルコードであり、実際のコードは要件に合わせて変更する必要があります。
- より詳細な情報は、Angular 公式ドキュメントや RxJS 公式ドキュメントを参照してください。
サービスにおける EventEmitter の代替方法
RxJS の BehaviorSubject を使う
// サービスファイル
import { BehaviorSubject } from 'rxjs';
export class MyService {
private someChangeSubject = new BehaviorSubject<SomeObject>(null);
someChange$ = this.someChangeSubject.asObservable();
constructor(private http: HttpClient) {}
getData() {
this.http.get('https://example.com/api/data').subscribe(data => {
this.someChangeSubject.next(data);
});
}
}
// コンポーネントファイル
import { MyService } from './my.service';
constructor(private myService: MyService) {}
ngOnInit() {
this.myService.someChange$.subscribe(obj => {
// データを受け取る
});
this.myService.getData();
}
メリット:
- 初期値を設定できる
- 常に最新の値を取得できる
Subject
よりも複雑
サービス内での状態管理
サービス内で BehaviorSubject
や Observable
を使わず、状態を直接管理することも可能です。
// サービスファイル
export class MyService {
private someData: SomeObject;
constructor(private http: HttpClient) {}
getData() {
return this.http.get('https://example.com/api/data').pipe(
tap(data => this.someData = data)
);
}
getSomeData() {
return this.someData;
}
}
// コンポーネントファイル
import { MyService } from './my.service';
constructor(private myService: MyService) {}
ngOnInit() {
this.myService.getData().subscribe(() => {
// データ取得完了後の処理
const data = this.myService.getSomeData();
// ...
});
}
- シンプルで分かりやすい
- RxJS の機能を活用していない
- 状態管理が複雑になる場合がある
その他のライブラリを使う
EventEmitter
や Subject
以外にも、データやイベントを伝達するためのライブラリが多数存在します。
これらのライブラリは、大規模なアプリケーションで状態管理を行う場合に有効です。
適切な方法の選択
- シンプルなアプリケーションであれば、サービス内での状態管理で十分
- 大規模なアプリケーションであれば、RxJS やその他のライブラリを使う
それぞれの方法のメリットとデメリットを理解し、適切な方法を選択することが重要です。
angular angular2-services