Как иметь функциональность ReplaySubject и BehaviorSubject

#angular #rxjs #behaviorsubject

#angular #rxjs #behaviorsubject

Вопрос:

У меня есть следующий код:

 class MyClass {
  private readonly clientId$: ReplaySubject<string>;

  public get clientId(): Observable<string> {
    return this.clientId$;
  }

  constructor([... things]) {
    this.clientId$ = new ReplaySubject<string>(1);
    
    someObservable
      .pipe(
        map(arg => {
          // business logic and what not...
        }))
      .subscribe(clientId => {
        this.clientId$.next(clientId);
      });
  }
}

  

Я хочу иметь возможность использовать myClassInstance.clientId.value(); , например, как объект поведения. В дополнение к новым подписчикам clientId , получающим старое значение, поскольку someObservable оно срабатывает нечасто.

Есть идеи? Заранее благодарю вас!

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

1. зачем вам это нужно? размер вашего буфера равен 1 для replaysubject, что существенно делает его похожим на BehaviourSubject.

2. Я хотел бы иметь возможность использовать его вне rxjs, как простое значение.

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

4. Синхронный геттер в BehaviorSubject любом clientId.value или clientId.getValue() нет clientId.value() . И это доступно только в BehaviorSubject . Если вам это нужно, вы можете использовать значение по умолчанию null для BehaviorSubject и не использовать его в подписке.

5. Это то, что BehaviorSubject делает a . Если вы подписываетесь на a BehaviorSubject , вы получаете его текущее (т. Е. Последнее) значение.

Ответ №1:

Хотя это не дает прямого ответа на ваш вопрос, я хотел бы отметить, что вам, вероятно, вообще не нужен subject!

Подписка на observable, просто для того, чтобы передать значение в свой собственный объект, обычно не требуется.

В вашем случае вам не нужен ReplaySubject, вам не нужен геттер, и вам не нужно подписываться в вашем конструкторе.

Это должно выполнить эту работу:

 class MyClass {
    constructor(private someService:SomeService) { }

    clientId$ = this.someService.someObservable.pipe(
        map(val => val.clientId)
    );
}
  

Что касается доступа к последнему значению… вы могли бы спрятать его в локальной переменной:

 clientId$ = this.someService.someObservable.pipe(
    map(val => val.clientId),
    tap(clientId => this.clientId = clientId)
);
  

Но часто в этом тоже нет необходимости. Если вы используете async канал в своем шаблоне, вы уже получаете развернутое последнее значение.

 <h3 *ngIf="clientId$ | async as clientId">{{ clientId }}</h3>
  

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

1. Есть тонкое, но важное отличие: проходя через многоадресную рассылку источника, ваш способ этого не делает. Если источник дорогой или не идемпотентный, как сетевой запрос, это становится большой проблемой. Конечно, многоадресная рассылка может быть достигнута с помощью операторов, которые скрывают объект, но все же используют объект.

2. Я также не уверен, какая часть вопроса заставляет вас сказать, что OP не нуждается в воспроизведении идентификатора клиента. Для этого есть много веских причин, нет информации о том, что они хотят делать, и нет информации о том, уже воспроизведен источник или нет.

3. И, наконец, ваш ответ пропускает различия в обработке ошибок по сравнению с исходным решением, что также может сыграть важную роль. В целом намерение здесь хорошее, но ответ недостаточно детализирован, чтобы слепо рекомендовать не использовать subject .

4. Спасибо, что указали на эти различия. Вы правы, важно знать о проблемах с множественным воспроизведением и обработкой ошибок и share при необходимости использовать shareReplay операторы or. Мое намерение состояло не в том, чтобы вообще избегать использования subjects, а в том, чтобы указать на то, что, я думаю, не очевидно для многих новичков rxjs, а именно: вам не нужно использовать Subject для ввода значений «вручную» через поток. Часто гораздо проще преобразовать существующий наблюдаемый поток в нужную вам форму.

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