Search code examples
angularngrx-store-4.0

ngrx/store 4: get unexpected sub state when selecting from store


I have several sub stores. Lets say Sub1 and Sub2 with the following states and reducers (actions are not interesting for my problem ... I guess):

Sub1:

export interface Sub1State {
  sub1value: string
}

export function sub1reducer(state: Sub1State, action: Action): Sub1State {
  ...
}

Sub2:

export interface Sub2State {
  sub2value: number
}

export function sub2reducer(state: Sub2State, action: Action): Sub2State {

}

Then I combine these two sub states into one ActionReducerMap<ApplicationState>:

export interface ApplicationState {
  sub1: Sub1State,
  sub2: Sub2State
}

export const reducers: ActionReducerMap<ApplicationState> = {
  sub1: sub1reducer,
  sub2: sub2reducer
};

And 'register' it to the Store:

StoreModule.forRoot(reducers)

Now, in a Angular component, I want to select the Sub1 store and get the sub1value string. So I do ...

sub1value$: Observable<string>;

constructor(private store: Store<Sub1State>) {
  this.sub1value$ = store.map(state => {
    console.log(state);
    return state.sub1value;
  });
}

In the log statement, I would expect to get the following object (the Sub1State object):

{
  sub1value: 'initial value'
}

But what I really get is this object:

{
  sub1: {
    sub1value: 'initial value'
  }
}

Is this working as intended? If yes, how shall I work with the interface Sub1State? Because sub1is not part of the interface.

And also curious is, I don't get any error (neither compiler error nor runtime error) when calling state.sub1value what is obviously wrong because it must be state.sub1.sub1value. No runtime error I understand, it is simply undefined. But the TypeScript compiler should throw an error here in my opinion.

I am really confused :/

EDIT

Here is an example of how I would expect it works: https://stackblitz.com/edit/angular-w34kua?file=app%2Fapp.component.ts


Solution

  • When you get the application's state, it is returning an object. Your state has two substates in it, they are called sub1 and sub2. Each of those is its own object. So it is working as expected. You would need to do 'return state.sub1.sub1value;

    Or what I usually do, is I subscribe to a specific reducer by doing something like this, then I only get that specific substate back and not the whole state:

    constructor(private store: Store<Sub1State>) {
      store.select('sub1').subscribe((state : Sub1State) => {
        console.log(state);
        this.sub1value$ = state.sub1value;
      });
    }