ngrx store Introduction - Tuong-Nguyen/Angular-D3-Cometd GitHub Wiki

workflow

Concepts

  • Store
    • Rx.Observable
    • Rx.Observer
    • Rx.BehaviorSubject = Rx.Observable + Rx.Observer (composition, variant of Rx.Subject)

dispatcher, reducer and state based on Rx.BehaviorSubject

  • Reducer: similar as reducer in Redux. It is a pure function (type of ActionReducer)
  • Action: similar as action in Redux. It is object composed of type and payload (optional)

Usages

  • Install ngrx/store
  • Create Action creator, Action Reducer
  • Connect Store to Module
  • Connect Store to Component

Install

npm install @ngrx/store @ngrx/effects @ngrx/router-store --save

Create Action, Reducer

API Document

Action

  • Implement Action interface
  • If action has data, override constructor with payload parameter
export const LOAD = '[WidgetManagement] Load';
export const LOAD_SUCCESS = '[WidgetManagement] Load Success';

/**
 * Load Collection Actions
 */
export class Load implements Action {
  readonly type = LOAD;
}

export class LoadSuccess implements Action {
  readonly type = LOAD_SUCCESS;

  constructor(public payload: Widget[]) {}
}

Reducer

  • Define a state interface for each feature's reducers and it's initial value (Shape of State)
export interface State {
  loading: boolean;
  loaded: boolean;
  items: Widget[];
}

export const initialState: State = {
  loading: false,
  loaded: false,
  items: []
};
  • A function has a state and an action as inputs. State is not mutate directly, returns a new state.
export function reducer(
  state = initialState,
  action: WidgetManagementActions.Actions
): State {
  switch (action.type) {
    case WidgetManagementActions.LOAD: {
      return Object.assign({}, state, {
        loading: true,
      });
    }

    case WidgetManagementActions.LOAD_SUCCESS: {
      const widgets = action.payload;

      return {
        loaded: true,
        loading: false,
        items: widgets,
      };
    }

    default: {
      return state;
    }
  }
}

NOTE: Unit test reducer?

Many reducers in a module?

  • Define module's state that combines reducers
  • Map module's state as a property of root's state
import * as fromWidgets from './widgets';
import * as fromRoot from '../../reducers';

export interface WidgetsState {
  widgets: fromWidgets.State;
}

export interface State extends fromRoot.State {
  widgets: WidgetsState;
}
  • Reducers for module
export const reducers = {
  widgets: fromWidgets.reducer
};

Connect To Module

  • Connect to root module
@NgModule({
  imports: [
    // ...
    StoreModule.forRoot(reducers),
  ],
  // ...
})
  • Connect to feature module
@NgModule({
  imports: [
    // ...
    StoreModule.forFeature('widgets', reducers),
  ],
  // ...
})

Connect to Component

  • Inject action creator and store through component's constructor
    • Store imported from 'ngrx/store'
constructor(private store: Store<fromWidgets.State>) {}
  • Get state, select function of store returns an observable
this.widgets$ = store.select(fromWidgets.getWidgets);

Store is an BehaviorSubject (ie: it is also a Observable and Observer and when it is subscribed, it emits the last emitted items to the observer).
When a component subscribes to Store, it will receive the current State.

  • Use async pipe to transform the observable in template
 <h4>Total Widgets: {{(widgets$ | async)?.length}}</h4>
  • Dispatch an action
import * as widgets from '../actions/widgets';
// ...
this.store.dispatch(new widgets.Load());

Effects & Selectors

https://github.com/Tuong-Nguyen/Angular-D3-Cometd/wiki/ngrx-store-Effects-&-Selectors

⚠️ **GitHub.com Fallback** ⚠️