RxJS — Отменить подписку, если наблюдаемое значение равно false, ожидая побочного эффекта

#angular #typescript #rxjs #ngrx

Вопрос:

У меня есть ситуация, в которой диалоговое окно может быть открыто, когда мы получаем обновление от BE через SSE, но закрыто, когда другое обновление изменяет предыдущее состояние.

Я создал вспомогательную функцию, которая вызывается изнутри effect и принимает в качестве параметра ссылку на открытый диалог. Там я подписываюсь на обновление статуса устройства, и если условие выполнено, диалоговое окно закрывается, и селектор должен быть отписан. Но он также должен быть отменен, когда пользователь закрывает диалоговое окно вручную. Теперь полученный код кажется мне очень странным.

 private closeOnStatusChange(dialog: MatDialogRef<ConfirmDialogComponent>): void {
  this.store
    .select(fromDevice.selectDeviceStatus)
    .pipe(
      map(({ deviceStatus }) => deviceStatus === DeviceStatus.INACTIVE || deviceStatus === DeviceStatus.FAILED),
      takeWhile(shouldClose => !shouldClose), // if status is 'ok', observe but do not unsubscribe
      takeUntil(dialog.afterClosed()),  // unsubscribe when dialog is closed
      filter(shouldClose => shouldClose), // status is 'fail', continue and close the dialog
      tap(() => dialog.close())
    )
    .subscribe();
}
 

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

Ответ №1:

Попробуйте использовать take — для этого требуется всего 1 событие и немедленно отпишитесь. Я дополнительно переключаю вас tap на подписку (но вы можете оставить ее после take(1) ). Код из головы — не проверялся

 .pipe(
      map(({ deviceStatus }) => deviceStatus === DeviceStatus.INACTIVE || deviceStatus === DeviceStatus.FAILED),
      takeWhile(shouldClose => !shouldClose), // if status is 'ok', observe but do not unsubscribe
      takeUntil(dialog.afterClosed()),  // unsubscribe when dialog is closed
      filter(shouldClose => shouldClose), // status is 'fail', continue and close the dialog
      take(1)
      )
.subscribe(() => dialog.close())
 

Комментарии:

1. Если он используется после filter , означает ли это, что я могу избежать takeWhile . Я никогда не был уверен в этом

2. @dallows Я не совсем понимаю ваш (основной) вопрос, но вы спрашиваете об отписке после того, как все сделано — поэтому я даю ответ на эту часть вашего вопроса. Однако, если у вас есть два источника событий — может быть, будет лучше описать это явным образом как две отдельные наблюдаемые, отфильтровать их — и объединить, используя, например merge , и затем take