Usando MergeMap com SwitchMap para resultar do NgRx Store

Oct 23 2020

Eu tenho 3 seletores:

  1. getUserInfo=> Para buscar ACNT detalhes (exemplo de saída: {acntId: 'A1'})
  2. getAllDepartments=> A lista de todos os dept Ids fetch (saída de exemplo: ['d1','d2'])
  3. 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

2 martin Oct 23 2020 at 14:55

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.

MrkSef Oct 24 2020 at 00:04

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);