BACK
Lessons46. Effects pattern: actions in, async work out
Lessons · 46

46. Effects pattern: actions in, async work out

What an effect is

If scan turns actions into state, an effect does something else: actions → side work (HTTP, a timer, a save) → new actions. This is the second half of the Redux/NgRx Effects pattern.

actions$.pipe(
  filter(a => a.type === 'save'),
  concatMap(a => api.save(a).pipe(map(() => ({ type: 'saved', id: a.id }))))
)

Why concatMap for saves

Saves must not be interleaved. Run two saves through mergeMap and, if the second finishes first, an old response could overwrite the newer state on the server. concatMap queues them — that's safe.

Your task

  1. In pipe, first filter(action => action.type === 'save').
  2. Then, comma-separated, concatMap(action => timer(20).pipe(map(() => ({ type: 'saved', id: action.id })))).
  3. The ignore action is filtered out, leaving two saves.

Deterministic check

This task's check runs in TestScheduler virtual time. If your solution is right, the console shows only Test Passed!. Don't add extra console.logs, or the check will fail.

Solution spoiler · click to reveal
const { Subject, timer, filter, concatMap, map } = Rx;

const actions$ = new Subject();

const effect$ = actions$.pipe(
  filter(action => action.type === 'save'),
  concatMap(action => {
    return timer(20).pipe(
      map(() => ({ type: 'saved', id: action.id }))
    );
  })
);
script.ts // TypeScript
CONSOLE · Console output
Hit Run to see the result...