NGRX - Run Function After Every Effect

Viewed 2518

Is it possible to have some sort of 'callback function' or watcher to an NGRX Effect? The use case is, I'm trying to persist state across browser refresh. I'd like to call my cache service to save the app state after each effect has run. Currently, I'm doing this by adding this to every effect:

tap(() => setTimeout(() => this.cacheService.saveAppState()))

It feels like there should be a better way to accomplish this?

4 Answers

Yes, there is a better way. You can implement OnRunEffects on the effects classes. For example:

@Injectable()
export class OrderStoreEffects implements OnRunEffects {
  // Resolves to either QueryCompleted or QueryFailed
  @Effect()
  queryOrdersFromProduct$: Observable<Action> = this.actions$.pipe(...);

  // Resolves to either QueryCompleted or QueryFailed
  @Effect()
  queryOrdersFromWorkCenter$: Observable<Action> = this.actions$.pipe(...);

  constructor(...) {}

  ngrxOnRunEffects(resolvedEffects$: Observable<EffectNotification>) {
    return resolvedEffects$.pipe(tap(effect => console.log({ effect })));
  }
}

The resolvedEffects$ observable emits every time that an effect in the OrderStoreEffects class is executed and resolved.

The emitted values look like this:

enter image description here

Which gives you some further possibilities to apply filters or other logic.

For more information about the OnRunEffects interface, check the docs

you don't need anything special. Write separate effect with function you've shown and just don't filter action type in it but go directly:

this.$actions.pipe(/* your logic here */)

so that will run for all actions.

now you can have withLatestFrom to get current state and do whatever you need with it.

[UPDATE]

This is something i'd not implement in effects but in canDeactivate router guards.

you can subscribe to ur effect for example:

this.store.dispatch(
        new YourActionEffect()
      );

 this.yourEffects.yourfunction.subscribe(
  (
    action:
      | yourActions.action1
      | yourActions.action2
  ) => {
    if (action === YourActionTypes.ACTION1) {
      //when action1 is fire
    }
    else {
      //when action2 is fire
    }
  }

I think that you'd be better off using effects for that.

What you really need is a hook to be warned after every store update. And this can be managed with meta reducers.

Hopefully, there's already a library that handles all of that for you!

Take a look here https://github.com/btroncone/ngrx-store-localstorage

Related