Использовать значение из httpClient после завершения - PullRequest
1 голос
/ 26 мая 2020

В моем проекте Angular (9) я получаю некоторые значения с помощью HttpClient из Rest-API. Я подписываюсь на него в разных местах (в основном с трубкой async, не напрямую, но все равно). Чтобы сделать его многоадресным, я "оборачиваю" результат HTTP-сервиса в BahaviorSubject:

const loadingDog = new BehaviorSubject<Dog|boolean>(true);
const subscription = this.getDogFromHttpClient(dogName)
   .pipe(map((dog: Dog|boolean) => this.someProecessing(dog)))
   .subscribe(loadingDog);
return loadingDog;

Я мог бы также использовать share Я думаю.

Собаки никогда изменение. Итак, чтобы избежать дублирования вызовов к содержимому stati c, сохраните loadingDog -Subjects в массиве и, если собака уже извлечена, верните сохраненный Subject из массива.


public dogs: BehaviorSubject<Dog|boolean>[] = [];

public getDog(name: string): BehaviorSubject<Dog|boolean> {

    if (isDefined(this.dogs[dogName])) {

        return this.dogs[dogName];
    }

   const loadingDog = new BehaviorSubject<Dog|boolean>(true);
   const subscription = this.http
          .get<Dog>(`https://dog.ceo/api/breed/${dogName}/images`)
          .pipe(map((dog: Dog|boolean) => this.someProcessing(dog)))
          .subscribe(loadingDog);

   this.dogs[dogName] = loadingDog;

   return loadingDog;
}


И в другом компоненты, которые я использую так:

  ngOnInit(): void {
    this.useMeInTemplate$ = dogService.getDog('akita').asObservable();
  }

Таким образом, компонент может решить, хочет ли он отображать знак загрузки или (в большинстве случаев), если наблюдаемое уже выполнено, контент. Работает отлично. Я показываю одну и ту же собаку во многих отношениях. Каждая подписка запускается по крайней мере один раз, с содержимым Dog или, если очень быстро, дважды, с состоянием загрузки (true в моем примере), а затем с содержимым.

Но если я хочу создать новый позже и повторно использовать наблюдаемое, это не сработает. Причина, по-видимому, в том, что HttpClient завершает Observable в какой-то момент, и, таким образом, завершается и упаковка BehaviorSubject.

Я создал пример на Stackblitz , где я поместил все в один компонент. Нажмите на div, чтобы увидеть, что он не работает;)

Думаю, моя упаковка httpClient могла быть сделана неправильно. Или у меня может быть более серьезное концептуальное заблуждение о том, как «кэшировать» httpResults? Или можно и нужно избегать завершения темы? Любая помощь приветствуется!

1 Ответ

1 голос
/ 26 мая 2020

вам нужно shareReplay(1), тогда каждый раз, когда кто-то подписывается, он будет получать последний известный ответ.

Что-то вроде этого.

public dogs = new Map<string, Observable<Dog|boolean>>();

public getDog(name: string): Observable<Dog|boolean> {
  if (!this.dogs.has(name)) {
    this.dogs.set(dogName, this.http
      .get<Dog|boolean>(`https://dog.ceo/api/breed/${name}/images`)
      .pipe(
        map(dog => this.someProcessing(dog)),
        shareReplay(1),
      ),
    );
  }
  return this.dogs.get(name);
}
...