Sunday, September 03, 2017

NGRX Store and State Management 2

In the first post I described what application state is and how to use it in your components.

Here we will get into modifying the state.

If you remember, our application State looked like this.

export interface Article {
   author: string;
   title: string;
}

export interface ArticleState {

   articlelist: Article[];
}

export interface State {
    articles: ArticleState;
    auth: AuthState;
    preferences: PreferencesState;

}

And we defined the reducers.


export function articlesreducer(state: ArticleState = InitialArticleState, action: Action) {}

On startup of the application we want the State to be usable as is in components, otherwise we would need to jump through hoops to check the existence of properties etc. On initialization the reducers are called with an undefined state parameter, so we can pass it an initialization value, here called InitialArticleState.

export const InitialArticleState: ArticleState = {
   articlelist: []

};

The ngFor in our template can handle an empty array without error.

State is modified by dispatching an action. How you define your actions is how your application logic will be executed. Victor Savkin wrote a blog post describing the types of messages you will use in your application. As your application grows having an established pattern for naming your actions makes it much easier to use.

So what actions do we need for our articles? We need to get them from somewhere. So we need a command action. And the articles need to be inserted into the store by a document type action.

An Action looks like this.

export interface Action {
  type: string;
}

To define them.

export const ARTICLES_LOAD = 'Load Articles';
export const ARTICLES = 'Article list';

export class ArticlesLoadAction: Action {
   type = ARTICLES_LOAD;
}

export class ArticlesAction: Action {
   type = ARTICLES;
   constructor(public payload: Articles[]) {}

export type Action 
   = ArticlesLoadAction
   | ArticlesAction;

The Articles reducer function would respond to these actions.

export const articlesreducer(state: ArticleState = InitialArticleState, action: fromArticles.Action) {
   switch (action.type) {
      case ARTICLES:
         return Object.assign({}, state, {
               articles: action.payload;
            }
         });
      default: return state;
   }
}

The ARTICLES action is responded by assigning the articles property with the array of articles. Each reducer is called with every action, so return state as the default case or the state will disappear into undefined. I don't respond to ArticlesLoad here because the state isn't modified by that action. A loading indicator could watch for Load actions if desired.

How to dispatch an action? 

constructor(private store: Store<State>) {
    this.store.dispatch( new ArticlesLoadAction());
}

An important point. State should be immutable; don't modify the state slice, return a new instance. If you are working with items in an array, don't push or pop, return a new instance of the array with the changes.

Reducers are very easy to test. Pass it an object and a type, then see what it spits out.

How do we get the articles?
And how do we break up our state/reducers into modules?

Comments: Post a Comment

Subscribe to Post Comments [Atom]





<< Home

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

Subscribe to Posts [Atom]