web-dev-qa-db-ja.com

RxJS SubjectまたはObservableの現在の値をどうやって取得しますか?

Angular 2サービスがあります。

import {Storage} from './storage';
import {Injectable} from 'angular2/core';
import {Subject}    from 'rxjs/Subject';

@Injectable()
export class SessionStorage extends Storage {
  private _isLoggedInSource = new Subject<boolean>();
  isLoggedIn = this._isLoggedInSource.asObservable();
  constructor() {
    super('session');
  }
  setIsLoggedIn(value: boolean) {
    this.setItem('_isLoggedIn', value, () => {
      this._isLoggedInSource.next(value);
    });
  }
}

すべてうまくいっています。しかし、購読する必要のない別のコンポーネントがあります。特定の時点でisLoggedInの現在の値を取得するだけです。これどうやってするの?

140
Baconbeastnz

SubjectまたはObservableは現在の値を持ちません。値が発行されると、それはサブスクライバに渡され、それとともにObservableが行われます。

現在の値を取得したい場合は、その目的のために設計されたBehaviorSubjectを使用してください。 BehaviorSubjectは最後に発行された値を保持し、それを直ちに新しい購読者に発行します。

現在の値を取得するためのメソッドgetValue()もあります。

243

should Observable/Subjectの「値」を取得する唯一の方法は、サブスクライブです!

getValue()を使用している場合は、宣言的なパラダイムで必須のことをしています。エスケープハッチとしてありますが、99.9%のgetValue()を使用すべきではありませんgetValue()が行う興味深いことがいくつかあります:エラーをスローしますサブジェクトがサブスクライブされていない場合、エラーなどのためにサブジェクトが死んでいる場合、値を取得できなくなります。しかし、まれに、エスケープハッチとして存在します。

「Rx-y」の方法でSubjectまたはObservableから最新の値を取得するには、いくつかの方法があります。

  1. BehaviorSubjectの使用:しかし実際にサブスクライブする。最初にBehaviorSubjectをサブスクライブすると、受信した、または初期化された前の値が同期的に送信されます。
  2. ReplaySubject(N)の使用:これはN値をキャッシュし、それらを新しいサブスクライバーにリプレイします。
  3. A.withLatestFrom(B):この演算子を使用して、オブザーバブルBが放出されたときに、オブザーバブルAから最新の値を取得します。配列[a, b]の両方の値を提供します。
  4. A.combineLatest(B):この演算子を使用して、AまたはBが出力するたびに、AおよびBから最新の値を取得します。両方の値を配列で提供します。
  5. shareReplay()ReplaySubjectを介してObservableマルチキャストを作成しますが、エラー時にObservableを再試行できます。 (基本的には、promise-yキャッシュ動作を提供します)。
  6. publishReplay()publishBehavior(initialValue)multicast(subject: BehaviorSubject | ReplaySubject)など:BehaviorSubjectおよびReplaySubjectを活用する他の演算子。同じことの異なるフレーバー、それらは基本的に、サブジェクトを介してすべての通知を集中させることにより、観測可能なソースをマルチキャストします。 connect()を呼び出して、件名でソースをサブスクライブする必要があります。
115
Ben Lesh

私は、値が到着した後に遅い購読者が件名を購読するという同様の状況を経験しました。

BehaviorSubjectに似ている ReplaySubject は、この場合魅力のように動作します。そして、これはより良い説明へのリンクです: http://reactivex.io/rxjs/manual/overview.html#replaysubject

5
Kfir Erez

私は最初はSubjectの現在の値を持っていなければならない子コンポーネントで同じ問題に遭遇しましたそしてそれから変更を聞くためにSubjectを購読します。私はサービス内の現在の値を維持するので、コンポーネントがアクセスできるようにします。 :

import {Storage} from './storage';
import {Injectable} from 'angular2/core';
import {Subject}    from 'rxjs/Subject';

@Injectable()
export class SessionStorage extends Storage {

  isLoggedIn: boolean;

  private _isLoggedInSource = new Subject<boolean>();
  isLoggedIn = this._isLoggedInSource.asObservable();
  constructor() {
    super('session');
    this.currIsLoggedIn = false;
  }
  setIsLoggedIn(value: boolean) {
    this.setItem('_isLoggedIn', value, () => {
      this._isLoggedInSource.next(value);
    });
    this.isLoggedIn = value;
  }
}

現在の値を必要とするコンポーネントは、サービスからその値にアクセスすることができます。

sessionStorage.isLoggedIn

これが正しい方法かどうかわからない:)

3
Molp Burnbright
const observable = of('response')

function hasValue(value: any) {
  return value !== null && value !== undefined;
}

function getValue<T>(observable: Observable<T>): Promise<T> {
  return observable
    .pipe(
      filter(hasValue),
      first()
    )
    .toPromise();
}

const result = await getValue(observable)
// Do the logic with the result
// .................
// .................
// .................

あなたはここからそれを実装する方法に関する記事全文をチェックすることができます。 https://www.imkrish.com/how-to-get-current-value-of-observable-in-a-clean-way/

1

それはやり過ぎに思えるかもしれませんが、これはObservabletypeを保ち、定型文を減らすための単なる「可能な」解決策です...

Observableの現在の値を取得するために、常にextension getterを作成できます。

これを行うには、Observable<T>タイピング宣言ファイルでglobal.d.tsインターフェースを拡張する必要があります。次に、extension getterobservable.extension.tsファイルに実装し、最後にタイピングと拡張子ファイルの両方をアプリケーションに含めます。

Angularアプリケーションに拡張子を含める方法については、この StackOverflow Answer を参照してください。

// global.d.ts
declare module 'rxjs' {
  interface Observable<T> {
    /**
     * _Extension Method_ - Returns current value of an Observable.
     * Value is retrieved using _first()_ operator to avoid the need to unsubscribe.
     */
    value: Observable<T>;
  }
}

// observable.extension.ts
Object.defineProperty(Observable.prototype, 'value', {
  get <T>(this: Observable<T>): Observable<T> {
    return this.pipe(
      filter(value => value !== null && value !== undefined),
      first());
  },
});

// using the extension getter example
this.myObservable$.value
  .subscribe(value => {
    // whatever code you need...
  });
0
j3ff