BehaviorSubject
でのデータ共有について、前提としてSubjectの理解もあった方が分かりやすかったため、併せて整理します。
Subjectとは
-
Subject
はObservable
による値の購読とObserver
による値を受け取り実行する、両方の機能を持つオブジェクト。 -
Observable
ではObserver
にユニキャストで値を送信していたが、Subject
ではObserver
にマルチキャストで値を送信できる。 -
Subject
ではObservable
にてコンシューマーに値を送信していたsubscriber
関数が不要。
Observable(ユニキャスト)
import { Observable } from 'rxjs';
const observable = new Observable(subscriber => {
subscriber.next("hoge");
subscriber.next("fuga");
subscriber.next("piyo");
});
observable.subscribe({
next: (v) => console.log(`observer1: ${v}`),
});
observable.subscribe({
next: (v) => console.log(`observer2: ${v}`),
});
// 表示 (observer1,observer2が直列で実行される)
// observer1: hoge
// observer1: fuga
// observer1: piyo
// observer2: hoge
// observer2: fuga
// observer2: piyo
Subject(マルチキャスト)
import { Subject } from 'rxjs';
const subject = new Subject<string>();
subject.subscribe({
next: (v) => console.log(`observer1: ${v}`),
});
subject.subscribe({
next: (v) => console.log(`observer2: ${v}`),
});
subject.next("hoge");
subject.next("fuga");
subject.next("piyo");
// 表示 (observer1,observer2が並列で実行される)
// observer1: hoge
// observer2: hoge
// observer1: fuga
// observer2: fuga
// observer1: piyo
// observer2: piyo
BehaviorSubjectとは
-
Subject
の機能に加え、最後に更新された値を保持することができるオブジェクト。 - コンストラクタにより初期値を設定することもできる。
- 値を保持することができるため、コンポーネント間でデータ共有も可能。
import { BehaviorSubject } from 'rxjs';
// 初期値を0で設定
const subject = new BehaviorSubject(0);
subject.subscribe({
next: (v) => console.log(`observer1: ${v}`),
});
subject.next(1);
subject.next(2);
subject.subscribe({
next: (v) => console.log(`observer2: ${v}`),
});
subject.next(3);
// 表示
// observer1: 0
// observer1: 1
// observer1: 2
// observer2: 2 ※最新の値を保持しているため、observer2は値2が送信された後でも受信できる
// observer1: 3
// observer2: 3
値を別コンポーネントで共有する場合
各ファイルの役割
- app.service.ts
- 初期値の設定
- 値の更新
- app.component.ts
- 値の購読
- app.component.html
- 値の表示
serviceのBehaviorSubject
を変更すると別コンポーネントでも値が更新されます。
app.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class AppService {
// 初期値の設定
public name = new BehaviorSubject<string>("test");
constructor() { }
changeName(name: string): void {
// 値の更新
this.name.next(name);
}
}
app.component.ts
import { Component, OnInit } from '@angular/core';
import { AppService } from './app.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit{
public name: string = "";
constructor(private appService: AppService) {}
ngOnInit(){
// 値の購読
this.appService.name.subscribe(name => {
this.name = name;
});
}
changeName(name: string): void {
this.appService.changeName(name);
}
}
app.component.html
<!-- 値の表示 -->
<p>{{name}}</p>
<input type="text" #newName>
<button (click)="changeName(newName.value)">名前変更</button>