Angular 2 でサービス、NgRedux/Store、EventBus を使用する方法
Angular 2 では、ルートスコープは廃止され、以下の3つの方法でコンポーネント間でデータを共有することができます。
コンポーネントのメンバー変数と @Input プロパティ
コンポーネントのメンバー変数は、そのコンポーネント内でのみアクセス可能なスコープ変数です。一方、@Input
プロパティは、他のコンポーネントから値を受け取るために使用されます。
// 親コンポーネント
@Component({
selector: 'app-parent',
template: `
<app-child [data]="data"></app-child>
`
})
export class ParentComponent {
data = 'Hello from parent!';
}
// 子コンポーネント
@Component({
selector: 'app-child',
template: `
<p>{{ data }}</p>
`
})
export class ChildComponent {
@Input() data: string;
}
サービスは、コンポーネント間で共有できるデータとロジックをカプセル化するためのクラスです。サービスは、DI (依存関係注入) を使用してコンポーネントに注入されます。
// サービス
@Injectable()
export class DataService {
private data = 'Hello from service!';
getData() {
return this.data;
}
}
// 親コンポーネント
@Component({
selector: 'app-parent',
template: `
<app-child [data]="dataService.getData()"></app-child>
`
})
export class ParentComponent {
constructor(private dataService: DataService) {}
}
// 子コンポーネント
@Component({
selector: 'app-child',
template: `
<p>{{ data }}</p>
`
})
export class ChildComponent {
constructor(private dataService: DataService) {}
get data() {
return this.dataService.getData();
}
}
NgRedux/Store は、アプリケーション全体の状態を管理するためのライブラリです。NgRedux/Store は、単一の状態ツリーを使用して、コンポーネント間でデータを共有します。
// store.ts
import { createStore } from 'redux';
const initialState = {
data: 'Hello from store!',
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case 'SET_DATA':
return { ...state, data: action.payload };
default:
return state;
}
};
const store = createStore(reducer);
export default store;
// 親コンポーネント
@Component({
selector: 'app-parent',
template: `
<app-child [data]="store.getState().data"></app-child>
`
})
export class ParentComponent {
constructor(private store: Store<AppState>) {}
}
// 子コンポーネント
@Component({
selector: 'app-child',
template: `
<p>{{ data }}</p>
<button (click)="updateData()">Update Data</button>
`
})
export class ChildComponent {
constructor(private store: Store<AppState>) {}
get data() {
return this.store.getState().data;
}
updateData() {
this.store.dispatch({ type: 'SET_DATA', payload: 'Hello from child!' });
}
}
これらの3つの方法のうち、どの方法を使用するかは、アプリケーションの要件によって異なります。
- コンポーネント間で単純なデータ共有を行う場合は、コンポーネントのメンバー変数と
@Input
プロパティを使用するのが最適です。 - 複雑なデータ共有やロジックを必要とする場合は、サービスを使用するのが最適です。
- アプリケーション全体の状態を管理する必要がある場合は、NgRedux/Store を使用するのが最適です。
補足
- Angular 2 では、ルートスコープを使用することは非推奨とされています。
- ルートスコープを使用する必要がある場合は、
@Injectable()
デコレータでデコレートされたサービスを作成し、そのサービスのコンストラクタで `
Angular 2におけるルートスコープの代替手段 - サンプルコード
コンポーネントのメンバー変数と @Input プロパティ
この例では、親コンポーネントから子コンポーネントへ文字列データを渡します。
親コンポーネント (app-parent.component.ts)
import { Component } from '@angular/core';
@Component({
selector: 'app-parent',
template: `
<app-child [data]="data"></app-child>
`
})
export class ParentComponent {
data = 'Hello from parent!';
}
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-child',
template: `
<p>{{ data }}</p>
`
})
export class ChildComponent {
@Input() data: string;
}
この例では、以下の点に注目してください。
- 親コンポーネント (
app-parent.component.ts
) は、data
というプロパティを持つ。このプロパティには、子コンポーネントに渡される文字列データが格納されている。 - 子コンポーネント (
app-child.component.ts
) は、@Input()
デコレータでデコレートされたdata
プロパティを持つ。このプロパティは、親コンポーネントから受け取るデータを受け取るために使用される。
サービス
この例では、サービスを使用して、2つのコンポーネント間で共有するデータとロジックをカプセル化します。
サービス (data.service.ts)
import { Injectable } from '@angular/core';
@Injectable()
export class DataService {
private data = 'Hello from service!';
getData() {
return this.data;
}
}
import { Component, Inject } from '@angular/core';
import { DataService } from './data.service';
@Component({
selector: 'app-parent',
template: `
<app-child [data]="dataService.getData()"></app-child>
`
})
export class ParentComponent {
constructor(private dataService: DataService) {}
}
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-child',
template: `
<p>{{ data }}</p>
`
})
export class ChildComponent {
@Input() data: string;
}
data.service.ts
ファイルには、DataService
というサービスが定義されている。このサービスは、data
というプロパティとgetData()
メソッドを持つ。- 親コンポーネント (
app-parent.component.ts
) は、DataService
をコンポーネントに注入するために@Inject()
デコレータを使用している。 - 子コンポーネント (
app-child.component.ts
) は、親コンポーネントからdata
プロパティを介してDataService
から取得したデータを受け取っている。
NgRedux/Store
この例では、NgRedux を使用して、アプリケーション全体の状態を管理します。
store.ts
import { createStore } from 'redux';
const initialState = {
data: 'Hello from store!',
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case 'SET_DATA':
return { ...state, data: action.payload };
default:
return state;
}
};
const store = createStore(reducer);
export default store;
import { Component, OnInit } from '@angular/core';
import { Store } from '@ngrx/store';
import { AppState } from './app.state';
@Component({
selector: 'app-parent',
template: `
Angular 2 におけるルートスコープの代替手段 - その他の方法
EventBus は、コンポーネント間でイベントを発行・購読するためのライブラリです。EventBus を使用して、コンポーネント間でデータを共有することができます。
BroadcastService は、コンポーネント間でメッセージをブロードキャストするためのサービスです。BroadcastService を使用して、コンポーネント間でデータを共有することができます。
各方法の比較
方法 | 利点 | 欠点 |
---|---|---|
コンポーネントのメンバー変数と @Input プロパティ | シンプルで分かりやすい | 複雑なデータ共有には向かない |
サービス | データとロジックをカプセル化できる | 複雑な依存関係になる可能性がある |
NgRedux/Store | アプリケーション全体の状態を管理できる | 学習曲線が険しい |
EventBus | コンポーネント間の疎結合を実現できる | イベントの管理が複雑になる可能性がある |
BroadcastService | シンプルなメッセージングに適している | 複雑なデータ共有には向かない |
RxJS | 非同期データ処理に適している | 学習曲線が険しい |
- 上記以外にも、様々な方法でコンポーネント間でデータを共有することができます。
- 最適な方法は、アプリケーションの要件と開発者のスキルによって異なります。
angular