Usando MergeMap com SwitchMap para resultar do NgRx Store
Eu tenho 3 seletores:
getUserInfo=> Para buscar ACNT detalhes (exemplo de saída:{acntId: 'A1'})getAllDepartments=> A lista de todos os dept Ids fetch (saída de exemplo:['d1','d2'])getAllDeptManagers=> para obter uma lista de gerentes de departamento para cada Id de departamento.
Agora, eu escrevi o código abaixo:
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);
})
);
De acordo com meu entendimento, mergeMapleva array e chama functionae achatar o array de observáveis retornado.
Estou recebendo ['d1','d2']todas as ligações para o seletor getAllDeptManagers. o que estou esperando é d1e então d2e assim por diante, e então obter todas as respostas de uma vez a partir deptsdo console.
Por favor ajude
Respostas
mergeMapnão nivela a saída de seu Observável interno. Ele apenas reemite quando o Observável interno emite e é isso. Portanto, parece que você deseja usar forkJoinaqui:
mergeMap(deptIds => forkJoin(
deptIds.map(deptId => this.store.select(getDepartmentManagers, {
departmentId: deptId
}).pipe(take(1)))
)),
Em seguida, os observadores receberão uma única matriz de resultados para deptIdsporque forkJoinaguardarão até que todos os Observavbles internos sejam concluídos.
A maneira mais simples de conseguir o que você deseja é mapear sua matriz em um fluxo. O primeiro switchMappega um valor e o mapeia em um fluxo. Esse stream emite um array, então você só precisa de mais um mergeMap. Como isso:
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);
Esse mergeMap parece engraçado (o bit extra) , mas se você retornar um array, ele será convertido em um fluxo. É semanticamente igual, mergeMap(depIdArr => from(depIdArr))mas com um pouco mais de desempenho.
Se virando uma matriz em um córrego e volta em uma matriz é demais, você pode combinar essas medidas com zip(), combineLatest()ou o que poderia ser melhor, neste caso: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);