Angular RxJS: событие сгенерировано дважды

Я закодировал две наблюдаемые:

Один для захвата событий отправки формы:

<form role = "form" (ngSubmit) = "search()">
   ...
</form>

И search() достигается и излучает:

private search(): void {
    this.searchClickSubject.next();
}

В конструкторе компонентов:

private searchClickSubject:Subject<void>;
private searchClick$:Observable<any>;

constructor() {
    this.searchClickSubject = new Subject<void>();
    this.searchClick$ = this.searchClickSubject.asObservable();
}

Как видите, я создаю Observable из темы searchClickSubject, используя метод searchClickSubject.asObservable для searchClick$.

С этого момента я использую этот searchClick$ Observable, чтобы ловить submit form.

После этого я создаю еще один Observable:

    this.searchQuery$ = this.searchClick$.pipe(
        map(() => <Query>{
            offset: 0,
            limit: 10
        })
    );

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

    this.metrics$ = this.searchQuery$
        .pipe(
          pageLoading(),
          makeRequest(),
          loadedPage()
        );

Это мой ngOnInit():

public ngOnInit() {            
    // Grab search button click event
    this.searchQuery$ = this.searchClick$.pipe(
        map(() => <Query>{
            offset: 0,
            limit: 10
        })
    );

    this.metrics$ = this.searchQuery$
        .pipe(
          //...
        );
}

Однако запрос запускается дважды.

Я создаю подписки с помощью конвейера async:

<div class = "row" *ngIf = "!(metrics$ | async)" style = "margin: 1.54em;">

<div *ngIf = "metrics$ | async; let metric;"...

Есть идеи?

Где вы подписаны на metrics$?

Dániel Barta 28.05.2019 13:33
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
2
1
690
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы подписываетесь на наблюдаемый metrics$ два раза. Вот что происходит:

  1. Вы подписываетесь с помощью *ngIf = "!(metrics$ | async)".
  2. Когда вы нажимаете поиск, он немедленно запускает наблюдаемый объект и все, что вы привязали к нему, включая ваш запрос.
  3. Вы подписываетесь с помощью *ngIf = "metrics$ | async; let metric;".
  4. Шаг 2 повторяется снова, отдельно.

Используйте оператор share() в metrics$, чтобы предотвратить повторный запрос на новую подписку. Если вы хотите глубже понять эту тему, ознакомьтесь с этим отличная статья.

Почему вы говорите, что я использую BehaviorSubject? Насколько мне удалось выяснить, я использую Subject<void> в качестве исходного источника, чтобы поймать отправку формы... С другой стороны... А как насчет ReplaySubject? Я думаю, что не стоит делиться и http-запросом...

Jordi 28.05.2019 14:57

Итак, я имею в виду, что оператор share() — это хороший обходной путь, но я думаю, что он пахнет таким «обходным решением». По ot и cold вопросам: сначала observable горячий (форма подчиняется), потом после switchMap превращается в холодный observable, не так ли?

Jordi 28.05.2019 15:03

Я не думаю, что это обходной путь в этом случае. У вас есть компонент, и в этом компоненте вы хотите, чтобы доля был одним и тем же наблюдаемым между двумя подписками. Вы правы, вы не используете ПоведениеТема, мой плохой, извините. Хотя ситуация такая же.

Dániel Barta 28.05.2019 16:05

Вы подписались на metrics$ два раза, вместо этого вы можете использовать синтаксис as, как показано ниже

<div *ngIf = "metrics$ | async as metric; else loading">
   <!-- Statements when metrics data found  -->
</div>

<ng-template #loading>
   <!-- Loading stuff...  -->
  <div class = "row" style = "margin: 1.54em;">
</ng-template>

Подробнее см. Обработка наблюдаемых с помощью NgIf и Async Pipe.

Другие вопросы по теме