我似乎不知道该使用哪个RxJS运算符来解决以下问题:
在我的音乐应用程序中,我有一个提交页面(就像一个音乐专辑)。要加载提交,我使用以下查询:
this.submissionId = parseInt(params['album']);
if (this.submissionId) {
this.submissionGQL.watch({
id: this.submissionId
}).valueChanges.subscribe((submission) => {
//submission loaded here!
});
}
很容易!但是,一旦加载了submission
,就必须加载一些辅助信息,例如当前的user
(以检查它们是否是提交的艺术家)和comments
。为了避免嵌套订阅,我可以修改以上查询,以在switchMap
解析后使用user
将查询流切换到comments
和submission
观察对象:
// stream to query for the submission and then switch query to user
this.submissionGQL.watch({
id: this.submissionId
}).valueChanges.pipe(
switchMap(submission => {
this.submission = submission;
return this.auth.user$
})
).subscribe((user) => {
// needs value of submission here
if (user.id == this.submission.user.id) {
//user is owner of submission
}
})
// stream to query for the submission and then switch query to comments
this.submissionGQL.watch({
id: this.submissionId
}).valueChanges.pipe(
switchMap(submission => {
this.comments$ = this.commentsGQL.watch({
submissionId: submission.id //needs submission response here
})
return this.comments$.valueChanges
})
).subscribe((comments) => {
this.comments = comments;
})
太好了!现在,我已经避免了嵌套订阅问题,但是每个submission
请求的第一部分是相同的。基本上,一旦查询submission
,我就想启动两个并行查询:
哪个RxJS运算符可以执行这样的操作?我想最后的订阅会发出一个数组响应,如:
.subscribe([user, comments] => {
// check if user == submission.user.id here
// also assign comments to component variable here
})
我相信mergeMap
是我所需要的,但是我不确定如何正确实现。还是在这种情况下,我应该share()
提交查询,然后分别构建并行查询?我很好奇!请让我知道,谢谢!
答案 0 :(得分:0)
尝试:
this.submissionGQL.watch({
id: this.submissionId
}).valueChanges.pipe(
switchMap(submission => {
this.submission = submission;
const user$ = this.auth.user$;
this.comments$ = this.commentsGQL.watch({
submissionId: submission.id
});
return combineLatest(user$, this.comments$);
}),
// maybe put a takeUntil to remove subscription and not cause memory leaks
).subscribe(([user, comments]) => {
// check if user == submission.user.id here
// also assign comments to component variable here
});
您应该考虑的是借助Angular(https://malcoded.com/posts/angular-async-pipe/)提供的async
管道来消除实例变量。
它将订阅可观察对象,将其显示在视图中,并在视图被破坏时自动退订。
因此,使用该代码,我们可以通过放置以下内容来摆脱this.submissions = submission
:
submissions$: Observable<ISubmission>; // assuming there is an interface of ISubmission, if not put any
// then when this.submissionId is defined
this.submissions$ = this.submissionGQL.watch({
id: this.submissionId
}).valueChanges;
// then when using it in your view you can do {{ this.submissions$ | async }}
this.comments$
同样适用。尽管所有这些都是可选的。在使用RxJS时,我会尽量减少实例变量,因为太多的实例变量会导致混乱。
然后,您可以从this.submissions$
开始观察并订阅其他主流。
this.submission$.pipe(
switchMap(submission => ..... // everything else being the same
)
我选择了combineLatest
运算符,但您可以根据需要使用zip
和forkJoin
。它们都有细微的差异(https://scotch.io/tutorials/rxjs-operators-for-dummies-forkjoin-zip-combinelatest-withlatestfrom)。
答案 1 :(得分:0)
在这种情况下,您可以使用RxJS forkJoin运算符。如文档所述,
所有可观测值完成后,从每个可观测值中发出最后一个发出的值。
const userQuery$ = this.submissionGQL.watch({
id: this.submissionId
}).valueChanges.pipe(
switchMap(submission => {
this.submission = submission;
return this.auth.user$
})
)
// stream to query for the submission and then switch query to comments
const commentsQuery$ = this.submissionGQL.watch({
id: this.submissionId
}).valueChanges.pipe(
switchMap(submission => {
this.comments$ = this.commentsGQL.watch({
submissionId: submission.id //needs submission response here
})
return this.comments$.valueChanges
})
)
forkJoin(userQuery$, commentsQuery$).subscribe([user, comments] => {
// check if user == submission.user.id here
// also assign comments to component variable here
})