👉今回の構成

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 {
...

簡単ですが以上です!!

元記事はこちら

キャッシュするHTTPクライアントをBehaviorSubjectを使って実装してみた例