簡體   English   中英

RxJS:使用另一個observable過濾一個observable

[英]RxJS : Filter one observable using another observable

我有一個流來自API響應的數據流,並有另一個流,它發出需要從源流中過濾的值。

@Injectable({
    providedIn: 'root'
})
export class SmpService {
    private _smp$ = new ReplaySubject(1);
    private _deleteSubject = new BehaviorSubject(null);

    constructor(private http: HttpClient) {
        const allSmp$ = this.loadSmp().pipe(map(list => list.map(item => item.id)));
        const delete$ = this._deleteSubject.pipe(map(value => this.filterSmp(value)));

        allSmp$
            .pipe(
                combineLatest(delete$, (notifications, xf) => {
                    return xf(notifications);
                }),
                tap(x => console.log('console ', x))
            )
            .subscribe(this._smp$);
    }

    loadSmp(): Observable<any> {
        const contextPath = 'some_url';
        const url = this.uriPrefix + contextPath;
        return this.http.get(url).pipe(map((response: any) => response.notifications || []));
    }

    filterSmp(value) {
        return notifications => notifications.filter(notification => value !== notification);
    }

    deleteSmp(subscribeItem) {
        this._deleteSubject.next(subscribeItem);
    }

    getSmp(): Observable<any> {
        return this._smp$.asObservable();
    }
}

過濾工作正常。 但是在頁面加載時,我無法在頁面上呈現初始API響應。 當我通過某個動作觸發deleteStream時,我才收到它。

即使沒有觸發deleteStream,我有什么辦法可以得到初始數據嗎?

而不是Subject使用BehaviorSubject具有一些默認值。 例如null

private _deleteSubject = new BehaviorSubject(null);

BehaviorSubject將在每次訂閱時發出默認值。

你遇到的主要問題可能是$delete是一個“冷”可觀察的,直到_deleteSubject有一個值。 如果你想在_deleteSubject給出任何值之前填充_smp$ ,那么你將需要使用默認值對其進行初始化,如@ m1ch4ls所述。

@Injectable({
    providedIn: 'root'
})
export class SmpService {

    private _smp$ = new ReplaySubject(1);
    private _deleteSubject = new BehaviorSubject(null);

    constructor(private http: HttpClient) {
        const allSmp$ = this.loadSmp().pipe(map(list => list.map(item => item.id)));
        const delete$ = this._deleteSubject.pipe(map(value => value ? this.filterSmp(value) : (notifications => notifications)));

        delete$
            .pipe(
                withLatestFrom(allSmp$, (xf, notifications) => {
                    return xf(notifications);
                }),
                tap(x => console.log('console ', x))
            )
            .subscribe(this._smp$);
    }

    loadSmp(): Observable<any> {
        const contextPath = 'some_url';
        const url = this.uriPrefix + contextPath;
        return this.http.get(url).pipe(map((response: any) => response.notifications || []));
    }

    filterSmp(value) {
        return (notifications) => notifications.filter(notification => value !== notification);
    }

    deleteSmp(subscribeItem) {
        this._deleteSubject.next(subscribeItem);
    }
}

另一種使用另一種方法過濾一個Observable的方法可以是

    private _smp$ = new ReplaySubject(1);
    private _deleteSubject = new Subject();

    constructor(private http: HttpClient) {
        const allSmp$ = this.loadSmp().pipe(map(list => list.map(item => item.id)));
        const delete$ = this._deleteSubject.pipe(
            map(value => (value ? this.filterSmp(value) : notifications => notifications))
        );

        allSmp$.merge(delete$)
            .pipe(
                startWith([]),
                scan((acc, value) => {
                    if (typeof value === 'function') {
                        return [...value(acc)];
                    }
                    return [...acc, ...value];
                })
            )
            .subscribe(this._smp$);
    }    

在此,我們做了以下事情:

  1. 已取代BehaviourSubject(null) -> Subject()
  2. 取代了combineLatest -> merge
  3. 添加了startWithscan以保持持久的內部狀態

瞧,它有效。 但仍在尋找其他更好的解決方案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM