Оператор RXJS для joinLatest без нулевых значений

В моем проекте Angular я пытаюсь получить значения нескольких селекторов ngrx и использовать их все для создания строки запроса, которая будет использоваться для вызова API.

Я хочу подождать, пока все они не выдадут ненулевое значение, а затем выдадут только один раз (чтобы вызов API не отправлялся несколько раз, если значения меняются со временем). Это решение, которое я получил:

const selectorA$ = this.store.select(...)
const selectorB$ = this.store.select(...)
const selectorC$ = this.store.select(...)

return combineLates([selectorA$, selectorB$, selectorC$]).pipe(
   first(list => list.every(item => item != null)),
   map(([selectorA, selectorB, selectorC]) => //... return query string using the store values)
)

Мне интересно, правильный ли это подход или есть ли встроенный оператор rxjs, который может дать мне такое поведение?

Спасибо

Тестирование функциональных 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
1
0
84
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете просто использовать joinLatest с фильтром, чтобы поток продолжался только тогда, когда присутствуют все три значения!

Если вам нужен только первый экземпляр, мы можем использовать takeUntil для завершения потока, когда будет отправлен первый действительный ввод!

private destroy$ = new Subject<void>();

const selectorA$ = this.store.select(...)
const selectorB$ = this.store.select(...)
const selectorC$ = this.store.select(...)

return combineLatest([selectorA$, selectorB$, selectorC$]).pipe(
   filter(list => list.every(item => item != null)),
   takeUntil(this.destroy$)
   map(([selectorA, selectorB, selectorC]) => { 
        // since we want only the first instance of valid input, we complete the subject, so that the stream is completed and no other events are taken! we use takeUntil for this!
        this.destroy$.next();
        this.destroy$.complete();
   })
)

Зачем нужна тема, takeUntil и карта с побочным эффектом вместо first() или take(1)?

maxime1992 28.03.2024 09:41

@ maxime1992, поскольку требованием вопроса является правильная комбинация всех трех наблюдаемых, не равная нулю, тогда только перестаньте прослушивать события! поэтому я использовал takeUntil

Naren Murali 28.03.2024 09:43

@AdiFuchs Этот ответ решает вашу проблему?

Naren Murali 28.03.2024 10:48

Возможно, это решится, но я изменил это, как сказал @maxime1992. поэтому сейчас я использую комбинированный селектор + first. надеюсь это хороший подход

Adi Fuchs 28.03.2024 10:56

@AdiFuchs, без проблем, спасибо, что уделили время!

Naren Murali 28.03.2024 10:56

@NarenMurali, просто чтобы ответить на твой последний ответ, но все равно все в порядке. combineLatest([selectorA$, selectorB$, selectorC$]).pipe(filter(list => list.every(item => item != null)), first()). Нет необходимости использовать внешнюю по отношению к потоку переменную класса, дублировать до тех пор, пока вручную не будет уничтожен/завершен объект на карте. Первый закроет поток, как только он получит значение, что происходит только после фильтра, что означает, что он будет действителен в этот момент.

maxime1992 28.03.2024 15:22
Ответ принят как подходящий

Никогда не делайте этого:

const selectorA$ = this.store.select(...)
const selectorB$ = this.store.select(...)
const selectorC$ = this.store.select(...)

return combineLatest([selectorA$, selectorB$, selectorC$]).pipe(...)

Представьте, что вы отправили действие, которое влияет на состояние (один раз), и все ваши селекторы здесь полагаются на это состояние, и три из них обновляются (по-прежнему одновременно). Каждый раз, когда ваши селекторы обновляются, ваш combineLatest будет излучать (по крайней мере, после того, как все они были изначально отправлены, что в магазине ngrx произойдет сразу же, поскольку вы всегда получаете эмиссию, как только подписываетесь на состояние).

Таким образом, ваш combineLatest потенциально сработает 3 раза вместо одного (после инициализации), когда произойдет новое обновление состояния.

Как это решить? Создайте новую выборку, которая объединит три нужных значения. Он будет излучать только один раз, когда это необходимо.

export const abc = createSelector(selectorA, selectorB, selectorC, (a, b, c) => ({ a, b, c }))

И заменить

const selectorA$ = this.store.select(...)
const selectorB$ = this.store.select(...)
const selectorC$ = this.store.select(...)

return combineLatest([selectorA$, selectorB$, selectorC$]).pipe(...)

С

this.store.select(abc)

При использовании вашего подхода я по-прежнему получаю значения как неопределенные. Как я могу быть уверен, что использую их только тогда, когда они готовы?

Adi Fuchs 28.03.2024 10:09

Вы все равно можете добавить filter(list => list.every(item => item != null)), а затем first() или take(1).

maxime1992 28.03.2024 15:23

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