31

I'm using a redux-style state management design with Angular and ngrx/store and ngrx/effects. Whenever I don't return an action from an effect, I get an error:

Cannot read property 'type' of undefined

I researched the issue and found that in an elm architecture there is something called a "noop" action that does nothing that you can call when you don't want to chain another action with your effect. Calling this noop action everywhere seems extremely repetitive to me. I am wondering if this would be a bad practice to follow. Is there a reason you cannot have an effect that does not return an action? Is the intention of effects to always have 1 action fire another action? I'm wondering if I am misunderstanding how to use effects.

Thanks!

Eeks33
  • 2,245
  • 1
  • 14
  • 17

1 Answers1

56

By default, an ngrx/effect dispatches an action.

If you want an effect to be 'fire-and-forget', all you need to do is add {dispatch: false} as an argument to the @Effects() decorator.

From the @ngrx/effects docs:

Observables decorated with the @Effect() decorator are expected to be a stream of actions to be dispatched. Pass { dispatch: false } to the decorator to prevent actions from being dispatched.

Usage:

class MyEffects {
  constructor(private actions$: Actions) { }
    
  @Effect({ dispatch: false }) logActions$ = this.actions$
    .do(action => {
      console.log(action);
    });
}

Under the hood, this is achieved with the ignoreElements operator. (Here is the source-code of ngrx/effects if you are interested). ignoreElements has a built in noop function that gets called every time the effect runs.

In short, there is no need for an explicit noop-action in ngrx/effects. I wouldn't outright call it 'bad practice' to dispatch a noop-action, but it is certainly not necessary when using ngrx.

mneumann
  • 713
  • 2
  • 9
  • 42
mtx
  • 1,662
  • 1
  • 18
  • 23
  • 2
    Good answer, but I'd suggest your changing the wording of *"This will complete the effects observable..."*. With observables, *complete* has a specific meaning and `{dispatch: false}` does not complete the observable. If it did, the effect would run only once. – cartant May 18 '17 at 22:34
  • You are right of course, the observable won't complete. I researched how ignoreElements works and it turns out it uses a noop-function itself. I changed my answer accordingly and made it a bit more concise, since I was reiterating what the docs say anyway :) Thanks! – mtx May 19 '17 at 05:37
  • Ah this makes sense. Great, strange how I missed this. Thanks! – Eeks33 May 19 '17 at 17:19
  • 3
    When using the newer pipeable operators use tap() instead of do(). – Will Tartak May 04 '18 at 16:05
  • 14
    If you use `createEffect` factory, just add `{ dispatch: false }` as its second parameter. – Neurotransmitter Apr 24 '20 at 10:58
  • 4
    What if you want to return an effect conditionally ? – Rox Teddy Apr 12 '21 at 15:44
  • @RoxTeddy It has been a while since I used Angular, so maybe there is a better way. But take a look at [this answer](https://stackoverflow.com/a/50975848/6745170). You could also go one step further and create two effects that filter the opposite condition of each other and then have one effect with `{ dispatch: false }` and the other returning an action. – mtx Apr 12 '21 at 16:32
  • An effect with conditional action is a very valid reason to require a no-op return value. – reads0520 Jul 08 '21 at 16:49