今回の構成
Angular4を使ってます。
今回の経緯
同じページで複数の子コンポーネントから同じリクエストを投げていたのを1回のリクエストで済ませたかった。
やったこと
HttpClientをもったサービスを作り、Getリクエストに対してBehaviorSubjectをObservableにして返すメソッドをはやした。
やってないこと
GETパラメータ対応とかやってない...
BehaviorSubjectの初期値を決めなきゃならなかったので配列限定にした...
とまあ実際にいろいろアプリに組み込む上であとで掲載するコードよりはもう少しファットになっているのですが、BehaviorSubject便利!の一つとしてシンプルに伝わればいいかなと思い省いています。
Subjectとは?
nextメソッドで流れてきた値をSubscriberに流す、SubscriberでありObservableなやつ
const subject = new Subject<number>();
subject.subscribe(number => console.log(number));
subject.next(1);
//出力: 1
BehaiviorSubjectとは?
Subjectに前回の値を保持する機能をもったもの。
.subscribeされたときに前回保持した値を最初に流す。
const behaiviorSubject = new BehaiviorSubject<number>(1); //Subjectと違い初期値をいれる必要あり
subject.subscribe(number => console.log(number)); //初期値が流れてくる
//出力: 1
subject.next(2);
//出力: 2
subject.subscribe(number => console.log(number));
//出力: 2
HTTPリクエストに使ってレスポンスを保持したもの
リクエストパスをキーに リクエストパス: BehaiviorSubject
のMapを持っている。
getメソッド呼び出し時に
MapになければHTTPリクエスト、
MapにあればBehaiviorSubjectをObservableにして返す。
といったことをしております。
export class CachedApiService {
private requestMap: Map<string, BehaviorSubject<any[]>> = new Map();
constructor(private http: HttpClient) {}
get<T>(path: string) {
if (!this.requestMap.get(path)) {
this.requestMap.set(path, new BehaviorSubject<T[]>([]));
this.http.get<T[]>(path, { params: this.params }).subscribe(
response => {
this.requestMap.get(path).next(response);
},
error => this.requestMap.get(path).error(error)
);
}
return this.requestMap.get(path).asObservable() as Observable<T[]>;
}
}
Angularでよかったこと
キャッシュ系っていつ更新するのか、とかどこに保持しておくのとか考える&管理するのが面倒なイメージだったのですが、AngularのServiceとして作ることで表示する一番親ページのproviderとして呼び出せば同じページ内だけ重複したリクエストが飛ばない仕様にでき楽でした。
以下呼び出すとき
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.scss'],
providers: [ CachedApiService ] // ← ここ
})
export class ParentComponent implements OnInit {
...
簡単ですが以上です!!