Saturday, July 22, 2017

Ngrx Platform

I've used ngrx/store and ngrx/effects for a while, and like the pattern. The new version has been released, and here are some of the changes I had to make in my code.

Pre v4 you built your reducers as follows, passing an object with

stateslice: reducerfunction.

const productionReducer = combineReducers(reducers);
export function reducers(state: any, action: any) {
    return productionReducer(state, action);}

With the new version, don't use combineReducers. I was running into the situation where the reducers weren't being initialized and the state was null.

Now you create your object of reducers:

export const reducer: ActionReducerMap = {
contactprimary: fromPrimary.reducer
contactselection: fromSelectionList.reducer
contactlist: undoable(fromContactList.reducer),
relations: relationUndoable(fromRelations.reducer),...

and in your app.module imports: [] section


StoreModule.forRoot(reducer),

The second big change is the Action type has been redefined.

export interface Action {
  type: string;
}

This breaks any of your code where you use action.payload. To fix it you have to define Action in each reducer. First define your action classes.

import {Action} from "@ngrx/store";
import {PrintItem} from "../../../models/print.model";


export const ADD_TO_QUEUE = '[Printing] Add to queue';
export const REMOVE_FROM_QUEUE = '[Printing] Remove from queue';
export const MARK_STATUS = '[Printing] mark status';

export class Print implements Action {
    type = ADD_TO_QUEUE;    
constructor(public payload: PrintItem) {}
}

export class PrintDone implements Action {
    type = REMOVE_FROM_QUEUE;    
constructor(public payload: PrintItem) {}
}

export class PrintStatus implements Action {
    type = MARK_STATUS;    
constructor(public payload: PrintItem) {}
}

export type Actions
    = Print
    | PrintStatus
    | PrintDone;


Note that the payload has a type in each one, and it is the same. You can call it whatever you like, or have multiple properties. The type Actions is exported.

Then in your reducer.

import {PrintState} from "../../../models/print.model";import {ActionReducer} from "@ngrx/store";import * as printingActionTypes from "../actions/printing.actions";

export type Action = printingActionTypes.Actions;
const initialState: PrintState = {
    queue: []
};
export const reducer: ActionReducer = (
    state = initialState, action: Action) => {
    switch (action.type) {
....


In this reducer, action is of the type defined in your action classes. The same action needs to be defined in the Effects as well.

This requires refactoring much of your reducers and effects. If you have different payloads for each of your defined action classes, lots of changes.

The advantage is strict typing of the data being passed around. It caught a couple minor flaws in my code, and I will be rewriting some reducers to take advantage of the added protection.

Otherwise it all works. The documentation is very helpful, especially with the specific initialization requirements.

I will update this blog after I have refactored the feature module reducers. There are also some improvements in the way selectors can be grouped.

Comments: Post a Comment

Subscribe to Post Comments [Atom]





<< Home

This page is powered by Blogger. Isn't yours?

Subscribe to Posts [Atom]