[x] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request
This was originally reported in #147 but it was closed by #153 even though the bug discussed there wasn't fixed.
I have a complex application with ngrx 4, only one root store (feature stores), some root effects, and lazyloading via the angular router.
When using AOT, at starts everything works fine but once the application is triggering a route (the component is lazy loaded but I'm not sure it is related since the store is already fully loaded at that point…) the actions are sent and visible via the redux devtools, but no change happens to the store.
I added some logging in one of the metareducers and it's clear that it doesn't even get there.
Things should work :)
I couldn't reproduce it on a small repro, but my application is publicly available.
$ git clone https://gitlab.com/linagora/petals-cockpit.git
$ cd petals-cockpit
$ git checkout 9994938472d2994f07fac6903f2f5735fd5a8be3
$ cd frontend
$ yarn
$ ng serve --prod -e=dev-e2e
Login with admin/admin: nothing happens!
While if you run it with ng serve -e=dev-e2e and login, it will load as expected.
Here is for the record my setup:
export const reducers: ActionReducerMap<IStore> = {
ui: UiReducer.reducer,
users: UsersReducer.reducer,
workspaces: WorkspacesReducer.reducer,
buses: BusesReducer.reducer,
busesInProgress: BusesInProgressReducer.reducer,
containers: ContainersReducer.reducer,
components: ComponentsReducer.reducer,
serviceUnits: ServiceUnitsReducer.reducer,
serviceAssemblies: ServiceAssembliesReducer.reducer,
sharedLibraries: SharedLibrariesReducer.reducer,
};
// if environment is != from production
// use storeFreeze to avoid state mutation
const metaReducersDev = [storeFreeze, enableBatching];
const metaReducersProd = [enableBatching];
export const metaReducers = environment.production
? metaReducersProd
: metaReducersDev;
And then use them as follows:
@NgModule({
imports: [
StoreModule.forRoot(reducers, { metaReducers }),
EffectsModule.forRoot([
WorkspacesEffects,
BusesInProgressEffects,
UsersEffects,
UiEffects,
BusesEffects,
ContainersEffects,
ComponentsEffects,
ServiceAssembliesEffects,
ServiceUnitsEffects,
SharedLibrariesEffects,
]),
// it'd be nice to have the possibility to activate redux devtools
// even if we're in prod but only with the extension
// since ngrx v4, no idea how to do that
!environment.production
? StoreDevtoolsModule.instrument({ maxAge: 50 })
: [],
...
],
providers,
})
export class CoreModule {}
CoreModule is then imported in the main AppModule.
node 8, typescript 2.4, ngrx 4.0.5, angular 4.1.3 and angular-cli 1.3.1.
And actually, it would be wiser to use the stable version of ngrx, because, as I told you in https://github.com/ngrx/platform/pull/153#issuecomment-317193210, #153 does break the build in some cases!
Also, we've tried to remove all the lazy loading in this app with @victornoel by making named functions exporting the required modules and using those functions with loadChildren but it didn't change anything. So the problem is probably not related to lazy loading
I updated the description to reference the correct commit which compiles with ngrx 4.0.1
I referenced the other problem in #191.
I've noticed a similar behavior in version 4. In my case, the reducer is only being fired for the last dispatch when there are multiple actions being dispatched from an effect. (not sure if it has to be an effect that dispatches the reducer action to cause this)
Work flow is as follows:
subscribe to the selector
dispatch Update action which is an effect that will...
dispatch UpdateSuccess action which is a reducer
subscription fires
I've added logging to verify that the Update action is dispatching the UpdateSuccess action but in the event of multiple Update actions being fired, even though each Update is dispatching the UpdateSuccess action, the logs in the UpdateSuccess action are only fired for the last UpdateSuccess action that is dispatched. It's almost like there is a debounce causing previous requests to be ignored.
My AOT build is broken aswell...
Does anyone have a small reproduction of this issue?
@brandonroberts you wouldn't happen to have a plunker with ngrx 4 that I can use to reproduce it, would you? I ask because all I see is version 2 in npmcdn.
@ShiftySituation sure. Here is a plunker template http://plnkr.co/edit/tpl:757r6L
@brandonroberts http://plnkr.co/edit/HQ5m02PYDxeIfsG180dz?p=preview
instead of calling 'increment' reducer directly, it sends it to an effect, which then calls the 'increment' reducer. I've added a delay in the effect so the 'increment' button can be clicked multiple times and you'll notice in the logs that the reducer only fires once.
@ShiftySituation you should use a mergeMap instead of a switchMap.
if you change that in your effect (you plnkr example) it handles all actions fine.
@littleStudent you are 100% right... it fixed the issue in my code as well. To conclude, my issue is a non-issue and therefore not related to the original issue.
I have the same problem. Coming from #250. I noticed something interesting: While my app does no longer crash with the nightly that fixes #250, the reducers function that I inject via an InjectionToken still seems to be not executed.
export function getReducers() {
console.log("Reducers function")
return {
entities: entityReducer, variables: variableReducer,
selectedVariable: selectVariableReducer,
cost: costReducer,
scenario: scenarioReducer, solution: solutionReducer,
level: difficultyReducer, levels: levelsReducer,
connectionState: connectionStateReducer, session: sessionReducer,
message: annaMessageReducer, messages: annaMessagesReducer,
moveVariable: moveVariableReducer
};
}
And I provide it like so:
{
provide: REDUCER_TOKEN,
useFactory: getReducers
}
However, in my log Reducers function never appears. While when I disable AOT it does.
With last night's nightly build it works for me perfectly with AOT now.
Can confirm this now works in the nightly build for me as well.
Hm, for me (nightly store) it's still broken.
Set a breakpoint in _createStoreReducers (store.es5.js), and inspect the values. injector is an injector, but reducers is actually my AppModule class. As in the constructor function. That's what came back from resolveNgModuleDep.
The dep being fetched was _INITIAL_REDUCERS, which is { useValue: reducers } in Store.forRoot(reducers, config).
I found a workaround, which is:
{ provide: _INITIAL_REDUCERS, useFactory: reducerMapFactory },
{ provide: INITIAL_REDUCERS, useFactory: reducerMapFactory },
(Note: cli 1.3.0, ngrx nightly, angular rest = 4.3.4, zone.js 0.8.16.)
My AOT build is still broken too...
Angular 4.3.4
Ngrx Platform 4.0.4
Uncaught TypeError: Cannot convert undefined or null to object
at Function.keys (<anonymous>)
export const ReducerTokenTest = new InjectionToken('Registered Reducers Test');
export const reducers = {
videos: TntReducer.registerReducer(VideoReducers, videosInitState),
comments: TntReducer.registerReducer(CommentReducers, commentsInitState),
tags: TntReducer.registerReducer(TagReducers, tagsInitState),
search: TntReducer.registerReducer(SearchReducers, searchInitState),
toasts: TntReducer.registerReducer(ToastReducer, toastInitState),
app: TntReducer.registerReducer(AppReducers, appInitState)
};
export const ReducerProvider = [
{provide: ReducerTokenTest, useValue: reducers}
];
StoreModule.forRoot(ReducerTokenTest, {metaReducers: MetaReducers}),
@Bretto use a factory to provide your reducers instead of a value.
export function getReducers() {
return reducers;
}
export const ReducerProvider = [
{ provide: ReducerTokenTest, useFactory: getReducers }
];
@brandonroberts is it correct to say the you shouldn't be able to tell the difference between a useValue- and a useFactory-injected value? I thought the injector black-boxed how a value was produced.
@cormacrelf I would say that's correct. I've found using a factory to be more reliable though in regards to AoT.
I had this problem with 4.0.0 - 4.0.2 but seems like 4.0.3 fixed the problem (in case of mine).
@brandonroberts Correct it fix my build. Thanks !
@brandonroberts for me it is still broken (I am not using a reducer token, but IÂ don't think it is related: the store is correctly setup, some reducers are executed at first and then it stops working).
You can do a repro with the following:
$ git clone https://gitlab.com/linagora/petals-cockpit.git
$ cd petals-cockpit
$ git checkout 9994938472d2994f07fac6903f2f5735fd5a8be3
$ cd frontend
$ yarn
$ ng serve --prod -e=dev-e2e
Login with admin/admin: nothing happens (but some reducers were triggered before, look at the events in the store devtools plugin) while if you do it with ng serve -e=dev-e2e the reducers are triggered as expected).
@Bretto It seems that I have the same issue as you had. How exactly did you solve it?
Just as @brandonroberts wrote
export const ReducerProvider = [
{ provide: ReducerTokenTest, useFactory: getReducers }
];
and then in the module:
StoreModule.forRoot(ReducerProvider, {metaReducers: MetaReducers})
?
@tschuege:
const reducerToken: InjectionToken: InjectionToken<ActionReducerMap<YourStateType>> =
new InjectionToken<ActionReducerMap<YourStateType>>('Reducers');
export const reducerProvider = { provide: reducerToken, useFactory: getReducers };
...in app.module
imports: [
StoreModule.forRoot(reducerToken, {...}),
...
],
providers: [
reducerProvider,
...
]
@halfmatthalfcat thanks!
But what is "YourStateType"?
I have an interface
export interface AllReducers {
reducer1: any,
redicer2: any
}
export const reducerToken: InjectionToken: InjectionToken<ActionReducerMap<AllReducers>> = new InjectionToken<ActionReducerMap<AllReducers>>('Reducers');
but then I get the ide error:
Cannot use new with an expression whose type lacks a call or construct signature.
YourStateType is just the type of your state that you'd put in the type definition for ActionReducerMap.
@tschuege
StoreModule.forRoot(ReducerTokenTest, {metaReducers: MetaReducers}),
export const ReducerTokenTest = new InjectionToken('Registered Reducers Test');
export const ReducerProvider = [
{provide: ReducerTokenTest, useFactory: getReducers}
];
providers: [
ReducerProvider,
...]
@Bretto and @halfmatthalfcat
Thanks for your help.
But it still doesn't work. I have no metaReducers, so I just do
StoreModule.forRoot(ReducerTokenTest, {});
in the imports of the app.module
It works on the first load (empty cache and hard reload). But after, when I do a normal reload I still get TypeError: Cannot convert undefined or null to object
Without AOT it all works fine
@tschuege Could you open another issue? Your problem is different than the
one discussed here originally :)
Le 22 août 2017 9:42 AM, "tschuege" notifications@github.com a écrit :
@Bretto https://github.com/bretto and @halfmatthalfcat
https://github.com/halfmatthalfcat
Thanks for your help.
But it still doesn't work. I have no metaReducers, so I just do
StoreModule.forRoot(ReducerTokenTest, {}),
It works on the first load (empty cache and hard reload). But after, when I
do a normal reload I still get TypeError: Cannot convert undefined or null
to object
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/ngrx/platform/issues/189#issuecomment-323945687, or mute
the thread
https://github.com/notifications/unsubscribe-auth/AAJ0z2K3a_9hB2lsb7kZHGmcyewjPYZXks5saoZbgaJpZM4Ojjuq
.
I updated the description to clarify what is the problem and put the repro steps in it as well as the correct environment versions :)
@victornoel my case was solved by using function(){} instead of arrow function in createSelector().
It seems like AOT is picky about arrow function. You might wanna check that.
@victornoel can you update your reproduction branch to a more recent version of Angular, @ngrx/effects version 4.0.5, and @ngrx/store version 4.0.3?
@brandonroberts it is already the case, I updated it (with the correct
instructions in the description) a few days ago.
Le 30 août 2017 3:58 AM, "Brandon" notifications@github.com a écrit :
@victornoel https://github.com/victornoel can you update your
reproduction branch to a more recent version of Angular, @ngrx/effects
version 4.0.5, and @ngrx/store version 4.0.3?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/ngrx/platform/issues/189#issuecomment-325855564, or mute
the thread
https://github.com/notifications/unsubscribe-auth/AAJ0z7Us5x3uLf-X2sKCjueFLH42blmDks5sdMGpgaJpZM4Ojjuq
.
@victornoel your package.json in the description is pinned to store 4.0.0, effects 4.0.1 and Angular 4.1.3 https://gitlab.com/linagora/petals-cockpit/blob/9994938472d2994f07fac6903f2f5735fd5a8be3/frontend/package.json
@brandonroberts sorry, I was sure I did it… but it seems it is not the case :)
Unfortunately, using the latest version of ngrx deps gives me this error during compile with AOT:
ERROR in /home/vnoel/Linagora/Petals/dev/git/petals-cockpit/frontend/src/$$_gendir/node_modules/@ngrx/store/store.ngfactory.ts (51,65): Argument of type '{}' is not assignable to parameter of type 'StoreFeature<any, any>[]'.
Property 'includes' is missing in type '{}'.
I will try to see if IÂ can fix this, I will ping you when it's ok (or if you have a solution? :)
Concerning Angular itself, we don't want to use a newer version because of https://github.com/angular/angular/issues/18129 but I can upgrade it for you to test if needed (because it only impacts dev mode).
@victornoel I believe the type error is a bug in the compiler in version 4.1.3. The error goes away if you upgrade to a version of Angular greater than 4.1.
@brandonroberts good news, indeed:
Sorry for not realising it sooner, I was convinced I already tried with latest :)
Great!
It doesn't seem like this is fixed. I read about a workaround with Object.assign(token, reducers) before initialising the module, but that also did not work for me. I made a reproduction, just download it, install deps and run it with ng serve and then ng serve --aot. In my case, the reducer completely vanishes in aot mode (see store devtools or the console output). I injected the feature reducers as written in the docs.
Edit: Angular Version 7.2.8, @ngrx/store 7.3.0
@lufonius move the feature module to its own separate file and it should work.
@timdeschryver hi, yes it's working now. Thanks a lot! I did not move it to a separate file as I had the same problem with a project at work, but the feature used to be in a separate file there. not quite sure now, what the problem is ... having a look at it :)
Most helpful comment
@Bretto It seems that I have the same issue as you had. How exactly did you solve it?
Just as @brandonroberts wrote
and then in the module:
StoreModule.forRoot(ReducerProvider, {metaReducers: MetaReducers})?