I'm in the process of migrating my app from ngrx 2 -> 4 and I'm having some issues with the init migration.
Previously I had:
@Effect()
init(): Observable<Action> {
return this.actions$
.ofType('@ngrx/effects/init')
.mergeMap(() => Observable.of(doSetup()));
}
Which I converted, based on the migration guide, to:
@Effect()
init(): Observable<Action> {
return Observable.defer(() => Observable.of(doSetup()));
}
in either case, I have another effect in the same class that's listening for the type returned by doInit:
@Effect()
onSetup(): Observable<Action> {
return this.actions$
.ofType(ActionTypes.doSetup)
.mergeMap(action => {
// contents elided
});
}
and this effect is not triggered at all. The action from init is dispatched, but isn't caught by onSetup, which is causing my app to stop working :/. There are no errors logged or any other diagnostic information I'm seeing, just the action being dispatched but not caught by the effect.
duplicated https://github.com/ngrx/platform/issues/103
I used #103 (and the update to the readme it triggered) to update my code to use defer. The problem here is that the effect that _uses_ defer is trying to kick off other effects, and these secondary effects don't get triggered at all.
In the example given, init is dispatching an action that onSetup is listening for, but onSetup never activates. It's registered, as observed by dropping a breakpoint and stepping through, but the body of the mergeMap is never invoked.
Move the init effect, the one with defer, to the bottom of the file. The sequence matters. I think we have discussed this in #103
Same as @maxisam I can confirm, that after moving the init$ with defer to the bottom, applicationInit$ is executed, BUT other actions, dispatched from component, using this.store.dispatch(new MyAction()); are not handled by effects.
So, I moved the defer and that worked as @maxisam explained, however that only seems to solve effects running in the same class. In my case, I need to kick off effects in multiple classes on init. Do I just need to refactor all of those to run on init themselves?
@berwyn I was in the same boat as you. So I refactor my code to use initialValue instead since my case is more like filling up initial values.
With the defer at the end of the classe, it is executed when the application init, but the other effects in the same classe are not triggered when there respective actions are dispatched.
This issue should be resolved in the latest release of @ngrx/effects. If that's not the case, please open a new issue.
The only way I can get this to work with the most current effects @brandonroberts is to use .delay on the .of in the deferred observable
@brandonroberts the latest (10/24) 4.1.0 version of @ngrx/effects suffers from the same issue; I had to move the defer(...) at the bottom.
@felikf have you tried the new ROOT_EFFECTS_INIT ?
need to import it like
import { Actions, Effect, ROOT_EFFECTS_INIT } from '@ngrx/effects';
It should work.
@maxisam / others: It seems to work when listening for ROOT_EFFECTS_INIT for effects that are registered in AppModule with forRoot, but what about when we register effects using forFeature in sub modules? They're not ready when ROOT_EFFECTS_INIT fires.
That makes sense, when you take the name ROOT_EFFECTS_INIT into consideration, but I'm not sure what is the correct way to make it work like it did in 2.x? Any ideas?
Maybe you could use the startWith operator?
In case this helps someone this solved my problem:
Changing:
import { defer, of } from 'rxjs/index' // suggested by IDE
to
import { defer, of } from 'rxjs'
Most helpful comment
@maxisam / others: It seems to work when listening for
ROOT_EFFECTS_INITfor effects that are registered in AppModule withforRoot, but what about when we register effects usingforFeaturein sub modules? They're not ready whenROOT_EFFECTS_INITfires.That makes sense, when you take the name
ROOT_EFFECTS_INITinto consideration, but I'm not sure what is the correct way to make it work like it did in 2.x? Any ideas?