将 MergeMap 与 SwitchMap 结合使用以从 NgRx Store 生成结果
Using MergeMap with SwitchMap to result from NgRx Store
我有 3 个选择器:
getUserInfo
=> 获取帐户详细信息(示例输出:{acntId: 'A1'}
)
getAllDepartments
=> 获取所有部门 ID 的列表(示例输出:['d1','d2']
)
getAllDeptManagers
=> 获取每个部门 Id 的部门经理列表。
现在,我写了下面的代码:
this.store
.select(getUserInfo)
.pipe(
switchMap((res) => this.store.select(getAllDepartments, { account: res.acntId})),
mergeMap(deptId => this.store.select(getDepartmentManagers,{departmentId: deptId }))
)
.subscribe((depts) => {
console.log(depts);
})
);
根据我的理解,mergeMap
获取数组并相应地调用 function
并展平返回的可观察数组。
我在每次调用选择器 getAllDeptManagers
时得到 ['d1','d2']
。我期待的是 d1
然后是 d2
等等,然后作为控制台的 depts
一次性获得所有响应。
请帮忙
mergeMap
不会展平其内部 Observable 的输出。它只是在内部 Observable 发射时重新发射,仅此而已。所以看起来你想在这里使用 forkJoin
:
mergeMap(deptIds => forkJoin(
deptIds.map(deptId => this.store.select(getDepartmentManagers, {
departmentId: deptId
}).pipe(take(1)))
)),
然后观察者将收到 deptIds
的单个结果数组,因为 forkJoin
将等待所有内部 Observbles 完成。
实现所需内容的最简单方法是将数组映射到流中。第一个 switchMap
获取一个值并将其映射到流上。该流发出一个数组,所以你只需要一个 mergeMap
。像这样:
this.store.select(getUserInfo).pipe(
switchMap(res => this.store.select(getAllDepartments, { account: res.acntId})),
mergeMap(depIdArr => depIdArr), // <- The extra bit
map(deptId => this.store.select(getDepartmentManagers,{departmentId: deptId })),
// Really, your source observables should be competeing,
// but if they don't take(1) should ensure that they do.
mergeMap(depMan$ => depMan$.pipe(take(1))),
toArray()
).subscribe(console.log);
那个 mergeMap 看起来很有趣 (额外的位),但是如果你 return 一个数组,它会被转换成一个流。它在语义上与 mergeMap(depIdArr => from(depIdArr))
相同,但性能更高。
如果将数组转换为流然后再转换回数组太多了,您可以将这些步骤与 zip()
、combineLatest()
或在这种情况下最好的方法结合起来:forkJoin()
this.store.select(getUserInfo).pipe(
switchMap(res => this.store.select(getAllDepartments, { account: res.acntId})),
map(deptIdArr => deptIdArr.map(
deptId => this.store.select(
getDepartmentManagers,{departmentId: deptId }
)
)),
// Really, your source observables should be completing,
// but if they don't take(1) should ensure that they do.
map(deptIdArrS => deptIdArrS.map(
deptId$ => deptId$.pipe(take(1))
),
mergeMap(deptIdArrS => forkJoin(deptIdArrS))
).subscribe(console.log);
我有 3 个选择器:
getUserInfo
=> 获取帐户详细信息(示例输出:{acntId: 'A1'}
)getAllDepartments
=> 获取所有部门 ID 的列表(示例输出:['d1','d2']
)getAllDeptManagers
=> 获取每个部门 Id 的部门经理列表。
现在,我写了下面的代码:
this.store
.select(getUserInfo)
.pipe(
switchMap((res) => this.store.select(getAllDepartments, { account: res.acntId})),
mergeMap(deptId => this.store.select(getDepartmentManagers,{departmentId: deptId }))
)
.subscribe((depts) => {
console.log(depts);
})
);
根据我的理解,mergeMap
获取数组并相应地调用 function
并展平返回的可观察数组。
我在每次调用选择器 getAllDeptManagers
时得到 ['d1','d2']
。我期待的是 d1
然后是 d2
等等,然后作为控制台的 depts
一次性获得所有响应。
请帮忙
mergeMap
不会展平其内部 Observable 的输出。它只是在内部 Observable 发射时重新发射,仅此而已。所以看起来你想在这里使用 forkJoin
:
mergeMap(deptIds => forkJoin(
deptIds.map(deptId => this.store.select(getDepartmentManagers, {
departmentId: deptId
}).pipe(take(1)))
)),
然后观察者将收到 deptIds
的单个结果数组,因为 forkJoin
将等待所有内部 Observbles 完成。
实现所需内容的最简单方法是将数组映射到流中。第一个 switchMap
获取一个值并将其映射到流上。该流发出一个数组,所以你只需要一个 mergeMap
。像这样:
this.store.select(getUserInfo).pipe(
switchMap(res => this.store.select(getAllDepartments, { account: res.acntId})),
mergeMap(depIdArr => depIdArr), // <- The extra bit
map(deptId => this.store.select(getDepartmentManagers,{departmentId: deptId })),
// Really, your source observables should be competeing,
// but if they don't take(1) should ensure that they do.
mergeMap(depMan$ => depMan$.pipe(take(1))),
toArray()
).subscribe(console.log);
那个 mergeMap 看起来很有趣 (额外的位),但是如果你 return 一个数组,它会被转换成一个流。它在语义上与 mergeMap(depIdArr => from(depIdArr))
相同,但性能更高。
如果将数组转换为流然后再转换回数组太多了,您可以将这些步骤与 zip()
、combineLatest()
或在这种情况下最好的方法结合起来:forkJoin()
this.store.select(getUserInfo).pipe(
switchMap(res => this.store.select(getAllDepartments, { account: res.acntId})),
map(deptIdArr => deptIdArr.map(
deptId => this.store.select(
getDepartmentManagers,{departmentId: deptId }
)
)),
// Really, your source observables should be completing,
// but if they don't take(1) should ensure that they do.
map(deptIdArrS => deptIdArrS.map(
deptId$ => deptId$.pipe(take(1))
),
mergeMap(deptIdArrS => forkJoin(deptIdArrS))
).subscribe(console.log);