Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nested reducers aren't working anymore with V4 #306

Closed
Braincompiler opened this issue Aug 21, 2017 · 6 comments
Closed

Nested reducers aren't working anymore with V4 #306

Braincompiler opened this issue Aug 21, 2017 · 6 comments

Comments

@Braincompiler
Copy link

I'm submitting a...


[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

What is the current behavior?

I have to migrate a huge codebase using ngrx@v2 to ngrx@v4 (Cause we need the better support for lazy-loaded modules). In v2 we were able to use combineReducers even with AOT but after migrating to v4 there will be either a compile error according to resolving symbol values statically or if I remove the combineReducers calls the reducers with nested reducers are missing on the state.

The compile error:

ERROR in Error encountered resolving symbol values statically. Calling function 'combineReducers', function calls are not supported. Consider replacing the function or lambda with a reference to an exported function, resolving symbol reducers in /Users/XXX/Projects/ngrx-bugs/ngrx-nested-reducers/src/app/reducers.ts, resolving symbol AppModule in /Users/XXX/Projects/ngrx-bugs/ngrx-nested-reducers/src/app/app.module.ts, resolving symbol AppModule in /Users/XXX/Projects/ngrx-bugs/ngrx-nested-reducers/src/app/app.module.ts, resolving symbol AppModule in /Users/XXX/Projects/ngrx-bugs/ngrx-nested-reducers/src/app/app.module.ts

If I use npm start (ng serve) the first round of compiling fails with the error above, if I change a file and trigger the watcher all the subsequent compilations will be successful and the reducers work as expected.

Expected behavior:

I want to use the current (nested) reducers (up to 5 levels deep in some cases). Of course I could flatten all the reducers but this would be a lot of refactoring I hope to avoid.

Minimal reproduction of the problem with instructions:

I created a small app which reproduces the behavior: https://github.com/Braincompiler/ngrx-nested-reducers (If you remove the combineReducers calls the state is empty).

@brandonroberts
Copy link
Member

brandonroberts commented Aug 21, 2017

You need to use a reducer token if you're calling a function like combineReducers to compose your reducers. https://github.com/ngrx/platform/blob/master/docs/store/api.md#injecting-reducers

app.module.ts

import { BrowserModule } from '@angular/platform-browser'
import { NgModule } from '@angular/core'
import { StoreModule } from '@ngrx/store'

import { AppRoutingModule } from './app-routing.module'
import { AppComponent } from './app.component'
import { reducers, reducerToken, reducerProvider } from './reducers';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    StoreModule.forRoot(reducerToken),
  ],
  providers: [reducerProvider],
  bootstrap: [ AppComponent ]
})
export class AppModule { }

reducers.ts

import { ActionReducerMap, combineReducers } from '@ngrx/store'

import * as fromApp from './appReducers'
import * as fromNested from './nestedReducers'
import { InjectionToken } from '@angular/core';

export interface IState {
    app: {
        a: fromApp.IState,
        b: fromNested.IState,
    }
}

export const reducers = combineReducers({
    a: fromApp.reducer,
    b: fromNested.reducer,
});

export const reducerToken = new InjectionToken<ActionReducerMap<IState>>('Reducers');

export function getReducers() {
    return {
      app: reducers,
    };
}

export const reducerProvider = [
    { provide: reducerToken, useFactory: getReducers }
];

@Braincompiler
Copy link
Author

Thanks a lot!

Ok, I supposed that but what if fromNested.reducer is a combination of yet another reducers? That's what I meant with "(up to 5 levels deep in some cases)".

Let's assume fromNested.reducer looks like that:

export const reducer = combineReducers({
  reducer1,
  reducer2,
  yetNestedReducer: fromYetNested.reducer,
  yetNestedReducer2: fromYetNested2.reducer,
  // ...
})

How do I realize it now?

Thanks a lot in advance. I really appreciate your help!

@brandonroberts
Copy link
Member

You don't have to do anything different in nesting your reducers. The only change is how they get registered with the NgModule so it's AoT compatible

@hagai26
Copy link

hagai26 commented Dec 17, 2017

There is a solution for nested reducers on V4 on this thread: ngrx/store#214 by @KwintenP

@mpaul31
Copy link

mpaul31 commented Jan 8, 2018

@brandonroberts anyway you could show code how it would look like with another level of reducer nesting like brians example?

@aaronfrost
Copy link

@brandonroberts if I use your exact same pattern with the exception that I am doing

StoreModule.forFeature('foo', fooReducerToken)

instead of

StoreModule.forRoot(fooReducerToken)

Does the forFeature change anything? I am guessing you will say no. But I am getting some ridiculous errors after this, and I am not sure what is going on.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants