我有一个流承载来自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,有什么方法可以获取初始数据?
答案 0 :(得分:0)
使用Subject
而不是BehaviorSubject
并使用一些默认值。例如null
。
private _deleteSubject = new BehaviorSubject(null);
BehaviorSubject
每次订阅都会发出默认值。
答案 1 :(得分:0)
您遇到的主要问题可能是$delete
是一个"cold",直到_deleteSubject
有了一个值。如果要在_smp$
被赋予任何值之前填充_deleteSubject
,则需要使用默认值对其进行初始化,如@ 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);
}
}
答案 2 :(得分:0)
可以使用另一种方法过滤一个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$);
}
在此,我们完成了以下操作:
BehaviourSubject(null) -> Subject()
combineLatest -> merge
startWith
和scan
以保持持久的内部状态瞧,它起作用了。但仍在寻找其他更好的解决方案。