Angularでコンポーネント間通信:EventEmitter vs Observable
Angularにおけるデリゲーション: EventEmitterとObservable
EventEmitterは、コンポーネント間でイベントを伝達するシンプルな方法です。イベント発生時に購読者に通知を送信し、購読者はそのイベントに応じた処理を実行できます。
EventEmitterの利点:
- 軽量で使いやすい
- シンプルなイベント伝達に適している
- コンポーネント間の直接的な結合を促進する
- 状態管理が煩雑になる
- イベントの順序制御が難しい *複雑なデータの伝達には不向き
Observableは、データストリームを表現する強力なツールです。データストリームとは、時間経過とともに変化するデータの連続的な流れです。Observableは、データストリームを購読し、データの変化を通知を受け取ることができます。
Observableの利点:
- データストリームを抽象化し、統一的に扱える
- 状態管理が容易
- イベントの順序制御やフィルタリングなどの高度な操作が可能
- 複雑なデータの伝達に適している
- EventEmitterよりも複雑で習得に時間がかかる
- すべてのユースケースに適しているわけではない
EventEmitterとObservableはそれぞれ異なる利点と欠点を持つため、ユースケースに応じて使い分ける必要があります。
- シンプルなイベント伝達にはEventEmitterが適しています。
- 複雑なデータの伝達や状態管理が必要な場合はObservableが適しています。
以下は、それぞれのユースケースの例です。
- ボタンクリックイベント
- フォーム入力イベント
- コンポーネント間の単純なデータ共有
- リアルタイムデータの更新
- Ajaxリクエスト
- 非同期処理
- 状態管理
EventEmitterとObservableは、Angularアプリケーションにおけるコンポーネント間通信の重要なツールです。それぞれの利点と欠点を理解し、ユースケースに応じて使い分けることが重要です。
EventEmitter
import { Component, OnInit, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'my-emitter',
templateUrl: './emitter.component.html',
})
export class EmitterComponent implements OnInit {
@Output() buttonClick = new EventEmitter<void>();
constructor() { }
ngOnInit() {
}
onClick() {
this.buttonClick.emit();
}
}
@Component({
selector: 'my-parent',
templateUrl: './parent.component.html',
})
export class ParentComponent implements OnInit {
constructor() { }
ngOnInit() {
}
onButtonClick() {
console.log('Button clicked!');
}
}
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
})
export class AppComponent {
constructor() { }
ngOnInit() {
}
}
<my-parent>
<my-emitter (buttonClick)="onButtonClick()"></my-emitter>
</my-parent>
parent.component.html
<h1>親コンポーネント</h1>
<button (click)="onButtonClick()">ボタンをクリック</button>
<h1>子コンポーネント</h1>
<button (click)="onClick()">ボタンをクリック</button>
Observable
import { Component, OnInit, Output, EventEmitter } from '@angular/core';
import { Observable, of } from 'rxjs';
@Component({
selector: 'my-observable',
templateUrl: './observable.component.html',
})
export class ObservableComponent implements OnInit {
@Output() buttonClick = new Observable<void>();
constructor() { }
ngOnInit() {
}
onClick() {
this.buttonClick = of(null);
}
}
@Component({
selector: 'my-parent',
templateUrl: './parent.component.html',
})
export class ParentComponent implements OnInit {
constructor() { }
ngOnInit() {
}
onButtonClick() {
console.log('Button clicked!');
}
}
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
})
export class AppComponent {
constructor() { }
ngOnInit() {
}
}
<my-parent>
<my-observable (buttonClick)="onButtonClick()"></my-observable>
</my-parent>
<h1>親コンポーネント</h1>
<button (click)="onButtonClick()">ボタンをクリック</button>
<h1>子コンポーネント</h1>
<button (click)="onClick()">ボタンをクリック</button>
上記のサンプルコードは、EventEmitterとObservableを使ったコンポーネント間通信の例です。それぞれのコードを参考に、ユースケースに応じて使い分けてください。
Angularにおけるコンポーネント間通信の他の方法
サービスは、コンポーネント間でデータを共有するために使用できるオブジェクトです。サービスはシングルトンとして登録されるため、アプリケーション全体で同じインスタンスが使用されます。
例:
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class MyService {
private data: string;
constructor() { }
setData(data: string) {
this.data = data;
}
getData() {
return this.data;
}
}
import { Component, OnInit } from '@angular/core';
import { MyService } from './my.service';
@Component({
selector: 'my-parent',
templateUrl: './parent.component.html',
})
export class ParentComponent implements OnInit {
constructor(private myService: MyService) { }
ngOnInit() {
this.myService.setData('Hello World!');
}
}
import { Component, OnInit } from '@angular/core';
import { MyService } from './my.service';
@Component({
selector: 'my-child',
templateUrl: './child.component.html',
})
export class ChildComponent implements OnInit {
constructor(private myService: MyService) { }
ngOnInit() {
const data = this.myService.getData();
console.log(data); // 'Hello World!'
}
}
依存関係注入は、コンポーネントにサービスを注入する方法です。コンポーネントクラスのコンストラクタにサービスを指定することで、コンポーネント内でサービスを使用することができます。
import { Component, OnInit, Inject } from '@angular/core';
import { MyService } from './my.service';
@Component({
selector: 'my-parent',
templateUrl: './parent.component.html',
})
export class ParentComponent implements OnInit {
constructor(
@Inject(MyService) private myService: MyService,
) { }
ngOnInit() {
this.myService.setData('Hello World!');
}
}
import { Component, OnInit, Inject } from '@angular/core';
import { MyService } from './my.service';
@Component({
selector: 'my-child',
templateUrl: './child.component.html',
})
export class ChildComponent implements OnInit {
constructor(
@Inject(MyService) private myService: MyService,
) { }
ngOnInit() {
const data = this.myService.getData();
console.log(data); // 'Hello World!'
}
}
ルーティングは、異なるコンポーネント間をナビゲートするために使用できます。URLに基づいてコンポーネントを表示したり、コンポーネント間でデータを渡したりすることができます。
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
@Component({
selector: 'my-parent',
templateUrl: './parent.component.html',
})
export class ParentComponent implements OnInit {
constructor(private router: Router) { }
ngOnInit() {
this.router.navigate(['/child', { data: 'Hello World!' }]);
}
}
import { Component, OnInit, ActivatedRoute } from '@angular/core';
@Component({
selector: 'my-child',
templateUrl: './child.component.html',
})
export class ChildComponent implements OnInit {
constructor(private activatedRoute: ActivatedRoute) { }
ngOnInit() {
const data = this.activatedRoute.snapshot.data['data'];
console.log(data); // 'Hello World!'
}
}
状態管理ライブラリ
NgRx Storeなどの状態管理ライブラリを使用して、コンポーネント間でデータを共有することができます。
import { Component, OnInit } from '@angular/core';
import { Store } from '@ngrx/
angular observer-pattern observable