Redux-observable: [Feature Request] Add "mapToAction" utility operator

Created on 23 Mar 2018  ·  3Comments  ·  Source: redux-observable/redux-observable

Do you want to request a feature or report a bug?

Request a feature

What is the current behavior?

Mapping observable notifications to actions can be verbose. Many effects that handle network effects often need map, catchError, and Observable.of to correctly map observable notifications to actions:

someNetworkRequest$
  .pipe(
    map(response => createSuccessAction(response)),
    catchError(error => Observable.of(createFailureAction(error))),
  );

For some effects (like those managing a WebSocket connection) they may also want to map the completion notification:

webSocketConnection$
  .pipe(
    map(message => createMessageAction(message)),
    catchError(error => Observable.of(createFailureAction(error))),
    concat(Observable.of(createCompletionAction())),
  );

What is the expected behavior?
Recommend adding a mapToAction helper operator that enables developers to more conveniently map observable notifications to actions:

webSocketConnection$
  .pipe(
    mapToAction(
      message => createMessageAction(action),
      error => createFailureAction(error),
      complete => createCompletionAction(),
    ),
  );

mapToAction would work similarly to observable$.subscribe() and tap where you can provide it optional functions for next, error, and complete or a partial observer.

If it gets approved here I will make the change to both redux-observable and ngrx/effects.

Which versions of redux-observable, and which browser and OS are affected by this issue? Did this work in previous versions of redux-observable?
All versions.

Most helpful comment

@wldcordeiro in v6 there is no concat pipeable operator anymore so _that code_ as-is doesn't work but the static factory function usage does:

import { concat, of } from 'rxjs';
import { map, catchError } from 'rxjs/operators';

concat(
  webSocketConnection$.pipe(
    map(message => createMessageAction(message)),
    catchError(error => Observable.of(createFailureAction(error)))
  ),
  of(createCompletionAction())
)

6.2 now has a endWith operator that makes this easier as well:

import { of } from 'rxjs';
import { map, catchError, endWith } from 'rxjs/operators';

webSocketConnection$.pipe(
  map(message => createMessageAction(message)),
  catchError(error => Observable.of(createFailureAction(error))),
  endWith(createCompletionAction())
)

All 3 comments

For some effects (like those managing a WebSocket connection) they may also want to map the completion notification:

Does that example work? I never tried that before but does concat of a "complete" action work as only being fired for completion versus after the map?

@wldcordeiro in v6 there is no concat pipeable operator anymore so _that code_ as-is doesn't work but the static factory function usage does:

import { concat, of } from 'rxjs';
import { map, catchError } from 'rxjs/operators';

concat(
  webSocketConnection$.pipe(
    map(message => createMessageAction(message)),
    catchError(error => Observable.of(createFailureAction(error)))
  ),
  of(createCompletionAction())
)

6.2 now has a endWith operator that makes this easier as well:

import { of } from 'rxjs';
import { map, catchError, endWith } from 'rxjs/operators';

webSocketConnection$.pipe(
  map(message => createMessageAction(message)),
  catchError(error => Observable.of(createFailureAction(error))),
  endWith(createCompletionAction())
)

@jayphelps that was actually what confused me, the fact that the pipeable was gone from my testing made me question what I was reading. endWith looks awesome but I hope it isn't affected by #254

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dance2die picture dance2die  ·  4Comments

pawelotto picture pawelotto  ·  3Comments

subhaze picture subhaze  ·  4Comments

rolele picture rolele  ·  5Comments

benlesh picture benlesh  ·  8Comments