Упрощенное внедрение Redux на Angular

Рано или поздно контроль состояния приложения становится сложнее и нужно внедрять менеджер состояний. Redux — отличная реализация такого менеджера, но хотелось бы постепенно погружаться, поэтому для себя написал небольшой шаблон сервиса на Angular с концепцией Redux.

Место изменения состояния становится единым, состояние можно изменить только оператором dispatch, при котором состояние меняется на новое.

Реализуем в классе функции createStore и dispatch, а также опишем редюсеры на события:

export class StoreService {

  initialState = {
    counter: 0,
    list: []
  };

  subject$: ReplaySubject<any>;

  handlers = {
    INCREMENT: state => ({ ...state, counter: state.counter + 1 }),
    DECREMENT: state => ({ ...state, counter: state.counter - 1 }),
    ADD: (state, action) => ({ ...state, counter: state.counter + action.payload }),

    ADDLIST: (state) => ({ ...state, list: state.list.concat(state.list.length + 1) }),

    DEFAULT: state => state
  };

  constructor() {
    this.subject$ = new ReplaySubject(1);
  }

  reducer = (state = this.initialState, action?) => {
    const handler = this.handlers[action.type] || this.handlers.DEFAULT;
    return handler(state, action);
  }

  createStore(rootReducer = this.reducer) {
    return this.subject$.asObservable()
      .pipe(
        startWith({ type: 'INIT' }),
        scan(rootReducer, undefined),
      );
  }

  dispatch(action) {
    this.subject$.next(action);
  }

}

Инициализируем стор:

export class HomePage implements OnInit {

  store$: Observable<any>;

  constructor(
    public storeService: StoreService
  ) {
  }

  ngOnInit() {
    this.store$ = this.storeService.createStore();
  }
}

Выведем данные из стора и опишем кнопки вызывающие события:

<ion-content>
  <ion-button (click)="storeService.dispatch({ type: 'INCREMENT' })">
    +
  </ion-button>
  <ion-button (click)="storeService.dispatch({ type: 'DECREMENT' })">
    -
  </ion-button>
  <ion-button (click)="storeService.dispatch({ type: 'ADD', payload: 10 })">
    +10
  </ion-button>
  <ion-input readonly [value]="(store$ | async).counter"></ion-input>

  <ion-button (click)="storeService.dispatch({ type: 'ADDLIST' })">
    +
  </ion-button>
  <ion-list>
    <ion-item *ngFor="let item of (store$ | async).list">{{ item }}</ion-item>
  </ion-list>
</ion-content>

Репозизатрий с примером.