ngrx/store

Do you have a hunch about what are we missing to properly combine child and parent?

josoroma-zz opened this issue · 1 comments

Looks like parent reducer is not properly combined or missing:

image

image

image

parent/components.ts

import { Component } from '@angular/core';

import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';

import { ParentActions } from './actions';
import { StoreWithParent, parentStoreFactory } from './reducer';

@Component({
  selector: 'parent-component',
  templateUrl: './component.html',
  providers: [{
    provide: StoreWithParent,
    useFactory: parentStoreFactory,
    deps: [Store]
  }]
})

export class ParentComponent {
  counter: Observable<number>;

  constructor(
    private actions: ParentActions,
    private store: StoreWithParent
  ) {
    console.log('ParentComponent - store ===>', store);

    this.counter = store.select(state => {
      console.log('ParentComponent this.store.select - state ===>', state);
      return state.parent.counter
    });
  }

  decrement() {
    this.store.dispatch(this.actions.decrement());
  }

  increment() {
    this.store.dispatch(this.actions.increment());
  }

  reset() {
    this.store.dispatch(this.actions.reset());
  }
}

parent/reducer.ts

import { Store, ActionReducer, Action, combineReducers } from '@ngrx/store';

import { AppState, createNewRootReducer } from './../../reducers/index';

import { ParentActions } from './actions';

export interface ParentState {
  counter: number;
}

const initialState: ParentState = {
  counter: 0
};

export function parentReducer(state: ParentState = initialState, action: Action) {
  switch (action.type) {

    case ParentActions.DECREMENT:
      return {
        ...state,
        counter: state.counter - 1
      };

    case ParentActions.INCREMENT:
      return {
        ...state,
        counter: state.counter + 1
      };

    case ParentActions.RESET:
      return {
        ...state,
        counter: 0
      };

    default:
      return state;
  }
}

export interface AppStateWithParent extends AppState {
  parent: ParentState;
}

export class StoreWithParent extends Store<AppStateWithParent> { }

export function parentStoreFactory(appStore: Store<AppState>) {
  appStore.replaceReducer(createNewRootReducer({ parent: parentReducer }));
  return appStore;
}

parent/child/component.ts

import { Component } from '@angular/core';

import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';

import { ChildActions } from './actions';
import { StoreWithChild, childStoreFactory } from './reducer';

@Component({
  selector: 'child-component',
  templateUrl: './component.html',
  providers: [{
    provide: StoreWithChild,
    useFactory: childStoreFactory,
    deps: [Store]
  }]
})

export class ChildComponent {
  counter: Observable<number>;

  constructor(
    private actions: ChildActions,
    private store: StoreWithChild
  ) {
    console.log('ChildComponent - store ===>', store);

    this.counter = store.select(state => {
      console.log('ChildComponent this.store.select - state ===>', state);
      return state.child.counter
    });
  }

  decrement() {
    this.store.dispatch(this.actions.decrement());
  }

  increment() {
    this.store.dispatch(this.actions.increment());
  }

  reset() {
    this.store.dispatch(this.actions.reset());
  }
}

parent/child/reducer.ts

import { Store, ActionReducer, Action, combineReducers } from '@ngrx/store';

import { AppState, createNewRootReducer } from './../../../reducers/index';

import { ChildActions } from './actions';

export interface ChildState {
  counter: number;
}

const initialState: ChildState = {
  counter: 0
};

export function childReducer(state: ChildState = initialState, action: Action) {
  switch (action.type) {

    case ChildActions.DECREMENT:
      return {
        ...state,
        counter: state.counter - 1
      };

    case ChildActions.INCREMENT:
      return {
        ...state,
        counter: state.counter + 1
      };

    case ChildActions.RESET:
      return {
        ...state,
        counter: 0
      };

    default:
      return state;
  }
}

export interface AppStateWithChild extends AppState {
  child: ChildState;
}

export class StoreWithChild extends Store<AppStateWithChild> { }

export function childStoreFactory(appStore: Store<AppState>) {
  appStore.replaceReducer(createNewRootReducer({ child: childReducer }));
  return appStore;
}

image

image

Thanks in advance!

I'm glad, I finally did it :)

Import the ChildModule in the ParentModule:

@NgModule({
    imports: [
        ...
        ChildModule
    ]
...
})

Manage the childReducer directly from the parentStoreFactory:

export const parentStoreFactory = (appStore: Store<AppState>) => {
 appStore.replaceReducer(
   createNewRootReducer({
     parent: parentReducer,
     child: childReducer
   })
 );

Dispatch a Parent Action from the ChildComponent:

...
reset() {
  this.store.dispatch(this.childActions.reset());
}

incrementParent() {
  this.store.dispatch(this.parentActions.increment());
}
...