LppEdd
LppEdd

Reputation: 21104

RxJS mergeMap doesn't behave as expected

I have this piece of RxJS code

this.listItems$ = this.store.select(EntityState.relationshipItems).pipe(
  map(fn => fn(12)),
  mergeMap(items => items),
  map(this.toListItem),
  toArray<ListItem>(),
  tap(x => console.log(x))
);

Using mergeMap(items => items) I'm trying to "flatten" the array, then map each item to another object, and then convert it back to an array.

However, the flow doesn't even reach the last tap. I can see the toListItem function is called, but I don't understand why it stops there.


Transforming it to

this.listItems$ = this.store.select(EntityState.relationshipItems).pipe(
  map(fn => fn(12)),
  map(items => items.map(this.toListItem)),
  tap(x => console.log(x))
);

makes it work, but I'd like to understand why the above one doesn't work.

Upvotes: 1

Views: 118

Answers (1)

martin
martin

Reputation: 96891

That's because this.store.select(...) is a Subject that never completes (if it did then you could select data just once which doesn't make sense).

However, toArray collects all emissions from its source and when its source completes it emits a single array. But the source is this.store.select(...) that never completes so toArray never emits anything.

So probably the easiest workaround would be just restructuring your chain:

this.listItems$ = this.store.select(EntityState.relationshipItems).pipe(
  map(fn => fn(12)),
  mergeMap(items => from(items).pipe(
    map(this.toListItem),
    toArray<ListItem>(),
    tap(x => console.log(x))
  )),
);

Now the source is from that completes after iterating items so toArray will receive complete notification and emit its content as well.

Upvotes: 1

Related Questions