我想点击一个可观察对象,以便在可观察对象的第一个值发出时执行一个方法。我想这样做,以便在UI中打开或关闭加载状态:
// Current .create observable
public create = (entry: EntryPatch): Observable<Entry> =>
this.http.post<NodeResponse<Entry>>(this.serviceEndpoint, entry).pipe(
map((response: NodeResponse<Entry>) =>
upsertNode<Entry>(response.data, this.entriesStore)))
public create = (entry: EntryPatch): Observable<Entry> =>
this.http.post<NodeResponse<Entry>>(this.serviceEndpoint, entry).pipe(
tapFirst(() => this.datastore.loading = true), // ⬅️ pseudocode
map((response: NodeResponse<Entry>) =>
upsertNode<Entry>(response.data, this.entriesStore)),
finalise(() => this.datastore.loading = false)) // ⬅️ switch off loading indicator
实现.tapFirst
运算符的最佳方法是什么(因为它实际上并不存在)?
正如@Lesiak在下面指出的那样,我上面提出的结构实际上是在响应从服务器返回而不是我本意的情况下启动加载指示符 。霍夫甚至以为原来的问题是错误的,我将把它讲出来,因为已经发布的答案仍然非常有帮助,并且可以解决这两个隐含的要求。
a)如何包装可观察的整个 b)如何检测第一次发射
答案 0 :(得分:2)
我认为有两种可能性
第一个:创建自定义运算符
function tapOnce<T>(fn: (value) => void) {
return (source: Observable<any>) =>
defer(() => {
let first = true;
return source.pipe(
tap<T>((payload) => {
if (first) {
fn(payload);
}
first = false;
})
);
});
}
请参见https://indepth.dev/create-a-taponce-custom-rxjs-operator/
第二个:拆分可观察对象
$coldObservable = sendMyRequest.pipe(shareReplay(1));
// subscribe to first
$coldObservable.pipe(first()).subscribe(/*do stuff with first emition*/);
// subscribe to all
$coldObservable.subscribe(/* do stuff with all emitions */);
答案 1 :(得分:1)
您可以结合使用tap()
和map()
来完成此操作,因为map()
还会为每个next
传递索引参数:
this.http.post()
.pipe(
map((response, index) => [response, index]),
tap(([response, index]) => {
if (index === 0) { ... }
}),
)
.subscribe(([response] => { ... })
您当然可以将所有内容放入map((response, index => {...})
中,然后只返回相同的response
对象,但是最好避免在map()
中产生副作用。