Part 3. Build your Pokédex: Improve NgRX using create* functions
Tags: javascript, angular, typescript, beginners
Published: 2019-08-19 22:53:42

---
title: Part 3. Build your Pokédex: Improve NgRX using create* functions
published: true
description: This post is part of a Series of post on which I'm describing how to build your Pokédex using NGRX from **beginner to ninja**, if you want to read more, you can read the following posts:
tags: javascript, angular, typescript, beginner
cover_image: https://cdn-images-1.medium.com/max/2000/0*0Y5OTBWR-YCcfel5.png
canonical_url: https://www.carloscaballero.io/build-your-pokedex-part-3-ngrx-entity-using-create-functions
series: pokedex-ngrx
---

This post is part of a Series of post on which I'm describing how to build your Pokédex using NGRX from **beginner to ninja**, if you want to read more, you can read the following posts:

* [Part 1. Build your Pokédex: Introduction to NGRX](https://carloscaballero.io/build-your-pokedex-part1-introduction-ngrx)
* [Part 2. Build your Pokédex: @ngrx/entity](https://carloscaballero.io/build-your-pokedex-part2-ngrx-entity)
* [Part 3. Build your Pokédex: Improve NgRX using create* functions](https://carloscaballero.io/build-your-pokedex-part-3-ngrx-entity-using-create-functions)
* Part 4. Build your Pokédex: @ngrx/data
* Part 5. Build your Pokédex: Testing NgRX

---

![cover-1](https://cdn-images-1.medium.com/max/2000/1*8z04ARQ6AeW6vz0OmRZFUw.png)

# Introduction
In this post, we will develop a **pokédex** using [Angular](http://angular.io) framework and [NgRX](https://ngrx.io) as a state management library. We will be using the new create* functions released with NgRX 8.


It is advisable to know how to manage Angular at an intermediate level and what a state management library is in order to understand this post properly. In this series, we will show how a specific example has been developed (Pokédex), which can be complement your NgRX learning.

First, the result of what will be built along these posts is shown in the following GIF.


![](https://cdn-images-1.medium.com/max/880/1*4rzmOje52kEmYCmSmGLPyg.gif)

It is essential to have read the [first](https://carloscaballero.io/build-your-pokedex-part1-introduction-ngrx) and [second](https://carloscaballero.io/build-your-pokedex-part2-ngrx-entity) parts of this series of posts to be able to understand what is being built. In this post we will improve the code previously developed in the series by using the create* functions from the `@ngrx/entity` package, which will simplify the boilerplate code needed to create actions, reducers and effects.

# createAction
In NgRX, a large amount of boilerplate code is needed when you want to create actions. You frequently need to create enums, action types, classes and union types. In this new version you can create actions in an easier way.


The NgRX core team have used the famous **factory function** design pattern to reach this goal. The factory function is **createAction**. The createAction function receives two parameters:

1. *action type*. Is the famous string used to identify the action.
2. *props*. Is the action metadata. For example, the **payload**.  


To compare both, the below codes illustrates how you can use the new **createAction** function in our Pokédex.

**before**
```typescript
export class LoadPokemon implements Action {
  readonly type = PokemonActionTypes.LOAD_POKEMONS;

  constructor() {}
}

export class LoadPokemonSuccess implements Action {
  readonly type = PokemonActionTypes.LOAD_POKEMONS_SUCCESS;

  constructor(public payload: Array<Pokemon>) {}
}
```

**after**
```typescript
loadPokemonFailed = createAction(
   PokemonActionTypes.LOAD_POKEMONS_FAILED,
   props<{ message: string }>()
 ),

add: createAction(PokemonActionTypes.ADD, props<{ pokemon: Pokemon }>()),
```

In the *before* code you need to create a class which implements the `Action` interface, define the `type` attribute and the `payload` using the constructor. On the other hand, in the *after* code you only need to create the action using the `createAction` function, where the first parameter is the `type` and the second parameter is the `props` attribute (in our context, it will be payload).

Although the core team states that the use of an enum is not required, in my particular coding style, I prefer to define an action enum to be aware of the action set.

Therefore, the *before* and *after* `pokemon.action.ts` are the following ones:

```typescript
import { Action } from '@ngrx/store';
import { Pokemon } from '@models/pokemon.interface';

export enum PokemonActionTypes {
  ADD = '[Pokemon] Add',
  ADD_SUCCESS = '[Pokemon] Add success',
  ADD_FAILED = '[Pokemon] Add failed',
  LOAD_POKEMONS = '[Pokemon] Load pokemon',
  LOAD_POKEMONS_SUCCESS = '[Pokemon] Load pokemon success',
  LOAD_POKEMONS_FAILED = '[Pokemon] Load pokemon failed',
  UPDATE = '[Pokemon] Update',
  UPDATE_SUCCESS = '[Pokemon] Update success',
  UPDATE_FAILED = '[Pokemon] Update failed',
  DELETE = '[Pokemon] Delete',
  DELETE_SUCCESS = '[Pokemon] Delete success',
  DELETE_FAILED = '[Pokemon] Delete failed'
}

export class LoadPokemon implements Action {
  readonly type = PokemonActionTypes.LOAD_POKEMONS;

  constructor() {}
}

export class LoadPokemonSuccess implements Action {
  readonly type = PokemonActionTypes.LOAD_POKEMONS_SUCCESS;

  constructor(public payload: Array<Pokemon>) {}
}
export class LoadPokemonFailed implements Action {
  readonly type = PokemonActionTypes.LOAD_POKEMONS_FAILED;

  constructor(public message: string) {}
}

export class Add implements Action {
  readonly type = PokemonActionTypes.ADD;

  constructor(public pokemon: Pokemon) {}
}

export class AddSuccess implements Action {
  readonly type = PokemonActionTypes.ADD_SUCCESS;

  constructor(public pokemon: Pokemon) {}
}
export class AddFailed implements Action {
  readonly type = PokemonActionTypes.ADD_FAILED;

  constructor(public message: string) {}
}

export class Delete implements Action {
  readonly type = PokemonActionTypes.DELETE;

  constructor(public id: number) {}
}
export class DeleteSuccess implements Action {
  readonly type = PokemonActionTypes.DELETE_SUCCESS;

  constructor(public id: number) {}
}
export class DeleteFailed implements Action {
  readonly type = PokemonActionTypes.DELETE_FAILED;

  constructor(public message: string) {}
}

export class Update implements Action {
  readonly type = PokemonActionTypes.UPDATE;

  constructor(public pokemon: Pokemon) {}
}
export class UpdateSuccess implements Action {
  readonly type = PokemonActionTypes.UPDATE_SUCCESS;

  constructor(public pokemon: Pokemon) {}
}
export class UpdateFailed implements Action {
  readonly type = PokemonActionTypes.UPDATE_FAILED;

  constructor(public message: string) {}
}

export type PokemonActions =
  | LoadPokemonSuccess
  | Add
  | AddSuccess
  | AddFailed
  | Delete
  | DeleteSuccess
  | DeleteFailed
  | Update
  | UpdateSuccess
  | UpdateFailed;
```

```typescript
import { createAction, props } from '@ngrx/store';

import { Pokemon } from '@models/pokemon.interface';

export enum PokemonActionTypes {
  ADD = '[Pokemon] Add',
  ADD_SUCCESS = '[Pokemon] Add success',
  ADD_FAILED = '[Pokemon] Add failed',
  LOAD_POKEMONS = '[Pokemon] Load pokemon',
  LOAD_POKEMONS_SUCCESS = '[Pokemon] Load pokemon success',
  LOAD_POKEMONS_FAILED = '[Pokemon] Load pokemon failed',
  UPDATE = '[Pokemon] Update',
  UPDATE_SUCCESS = '[Pokemon] Update success',
  UPDATE_FAILED = '[Pokemon] Update failed',
  REMOVE = '[Pokemon] Delete',
  REMOVE_SUCCESS = '[Pokemon] Delete success',
  REMOVE_FAILED = '[Pokemon] Delete failed'
}

export const actions = {
  loadPokemon: createAction(PokemonActionTypes.LOAD_POKEMONS),
  loadPokemonSuccess: createAction(
    PokemonActionTypes.LOAD_POKEMONS_SUCCESS,
    props<{ pokemons: Pokemon[] }>()
  ),
  loadPokemonFailed: createAction(
    PokemonActionTypes.LOAD_POKEMONS_FAILED,
    props<{ message: string }>()
  ),
  add: createAction(PokemonActionTypes.ADD, props<{ pokemon: Pokemon }>()),
  addSuccess: createAction(
    PokemonActionTypes.ADD_SUCCESS,
    props<{ pokemon: Pokemon }>()
  ),
  addFailed: createAction(
    PokemonActionTypes.ADD_FAILED,
    props<{ message: string }>()
  ),
  remove: createAction(PokemonActionTypes.REMOVE, props<{ id: number }>()),
  removeSuccess: createAction(
    PokemonActionTypes.REMOVE_SUCCESS,
    props<{ id: number }>()
  ),
  removeFailed: createAction(
    PokemonActionTypes.REMOVE_FAILED,
    props<{ message: string }>()
  ),
  update: createAction(
    PokemonActionTypes.UPDATE,
    props<{ pokemon: Pokemon }>()
  ),
  updateSuccess: createAction(
    PokemonActionTypes.UPDATE_SUCCESS,
    props<{ pokemon: Pokemon }>()
  ),
  updateFailed: createAction(
    PokemonActionTypes.UPDATE_FAILED,
    props<{ message: string }>()
  )
};
```

I have exported an `action` const, which is a dictionary that contains the action name as key and the action itself as value.


*createAction* is a factory function that returns a function, called an ActionCreator, which returns an action object when called. Therefore, you have to invoke the ActionCreator when you want dispatch an action:

```typescript
this.store.dispatch(addSuccess(pokemon: Pokemon));
```

It is no longer necessary to create an object associated with the class of the action, you can now invoke the function directly.

Because of this, the following refactoring must be applied to all the effects in which actions are created:


**before**
```typescript
@Effect()
loadAllPokemon$: Observable<any> = this.actions$.pipe(
  ofType(PokemonActions.PokemonActionTypes.LOAD_POKEMONS),
  switchMap(() =>
    this.pokemonService.getAll().pipe(
    map(pokemons => new PokemonActions.LoadPokemonSuccess(pokemons)),
      catchError(message => of(new PokemonActions.LoadPokemonFailed(message)))
    )
  )
);
```

**after**
```typescript
@Effect()
loadAllPokemon$: Observable<any> = this.actions$.pipe(
    ofType(PokemonActions.loadPokemon),
    switchMap(() =>
      this.pokemonService.getAll().pipe(
        map(pokemons => PokemonActions.loadPokemonSuccess({ pokemons })),
        catchError(message => of(PokemonActions.loadPokemonFailed({ message }))
          )
        )
      )
    )
  );
```

The effects themselves will be refactored in the next section using the **createEffects** function.

# createEffects
NgRx 8 provides the `createEffect` method which is an alternative to the `@Effect()` decorator. The main advantage of using `createEffect` instead of the decorator is that it's type safe. That is, if the effect does not return an `Observable<Action>` it will throw compile errors. 

In the following code fragment I will show you the `loadAllPokemon$` effect before and after applying the new `createEffect` method. The migration is very easy.

**before**
```typescript
@Effect()
loadAllPokemon$: Observable<any> = this.actions$.pipe(
    ofType(PokemonActions.loadPokemon),
    switchMap(() =>
      this.pokemonService.getAll().pipe(
        map(pokemons => PokemonActions.loadPokemonSuccess({ pokemons })),
        catchError(message => of(PokemonActions.loadPokemonFailed({ message }))
          )
        )
      )
    )
  );
```

**after**
```typescript
loadAllPokemon$ = createEffect(() =>
    this.actions$.pipe(
      ofType(PokemonActions.loadPokemon),
      switchMap(() =>
        this.pokemonService.getAll().pipe(
          map(pokemons => PokemonActions.loadPokemonSuccess({ pokemons })),
          catchError(message =>
            of(PokemonActions.loadPokemonFailed({ message }))
          )
        )
      )
    )
  );
```

Therefore, the *before* and *after* `pokemon.effects.ts` are the following ones:

**before**
```typescript
import * as PokemonActions from '@states/pokemon/pokemon.actions';

import { Actions, Effect, ofType } from '@ngrx/effects';
import { Observable, of } from 'rxjs';
import { catchError, map, switchMap, tap } from 'rxjs/operators';

import { Injectable } from '@angular/core';
import { MatSnackBar } from '@angular/material';
import { Pokemon } from '@shared/interfaces/pokemon.interface';
import { PokemonService } from '@services/pokemon.service';

@Injectable()
export class PokemonEffects {
  constructor(
    private actions$: Actions,
    private pokemonService: PokemonService,
    public snackBar: MatSnackBar
  ) {}

  POKEMON_ACTIONS_SUCCESS = [
    PokemonActions.PokemonActionTypes.ADD_SUCCESS,
    PokemonActions.PokemonActionTypes.UPDATE_SUCCESS,
    PokemonActions.PokemonActionTypes.DELETE_SUCCESS,
    PokemonActions.PokemonActionTypes.LOAD_POKEMONS_SUCCESS
  ];

  POKEMON_ACTIONS_FAILED = [
    PokemonActions.PokemonActionTypes.ADD_FAILED,
    PokemonActions.PokemonActionTypes.UPDATE_FAILED,
    PokemonActions.PokemonActionTypes.DELETE_FAILED,
    PokemonActions.PokemonActionTypes.LOAD_POKEMONS_FAILED
  ];

  @Effect()
  loadAllPokemon$: Observable<any> = this.actions$.pipe(
    ofType(PokemonActions.PokemonActionTypes.LOAD_POKEMONS),
    switchMap(() =>
      this.pokemonService.getAll().pipe(
        map(response => new PokemonActions.LoadPokemonSuccess(response)),
        catchError(error => of(new PokemonActions.LoadPokemonFailed(error)))
      )
    )
  );

  @Effect()
  addPokemon$: Observable<any> = this.actions$.pipe(
    ofType(PokemonActions.PokemonActionTypes.ADD),
    switchMap((action: any) =>
      this.pokemonService.add(action.pokemon).pipe(
        map((pokemon: Pokemon) => new PokemonActions.AddSuccess(pokemon)),
        catchError(error => of(new PokemonActions.AddFailed(error)))
      )
    )
  );

  @Effect()
  deletePokemon$: Observable<any> = this.actions$.pipe(
    ofType(PokemonActions.PokemonActionTypes.DELETE),
    switchMap(({ id }) =>
      this.pokemonService.delete(id).pipe(
        map(() => new PokemonActions.DeleteSuccess(id)),
        catchError(error => of(new PokemonActions.DeleteFailed(error)))
      )
    )
  );

  @Effect()
  updatePokemon$: Observable<any> = this.actions$.pipe(
    ofType(PokemonActions.PokemonActionTypes.UPDATE),
    switchMap(({ pokemon }) =>
      this.pokemonService.update(pokemon).pipe(
        map(() => new PokemonActions.UpdateSuccess(pokemon)),
        catchError(error => of(new PokemonActions.UpdateFailed(error)))
      )
    )
  );

  @Effect({ dispatch: false })
  successNotification$ = this.actions$.pipe(
    ofType(...this.POKEMON_ACTIONS_SUCCESS),
    tap(() =>
      this.snackBar.open('SUCCESS', 'Operation success', {
        duration: 2000
      })
    )
  );
  @Effect({ dispatch: false })
  failedNotification$ = this.actions$.pipe(
    ofType(...this.POKEMON_ACTIONS_FAILED),
    tap(() =>
      this.snackBar.open('FAILED', 'Operation failed', {
        duration: 2000
      })
    )
  );
}

```

**after**
```typescript
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { catchError, map, switchMap, tap } from 'rxjs/operators';

import { Injectable } from '@angular/core';
import { MatSnackBar } from '@angular/material';
import { Pokemon } from '@shared/interfaces/pokemon.interface';
import { actions as PokemonActions } from '@states/pokemon/pokemon.actions';
import { PokemonService } from '@services/pokemon.service';
import { of } from 'rxjs';

@Injectable()
export class PokemonEffects {
  constructor(
    private actions$: Actions,
    private pokemonService: PokemonService,
    public snackBar: MatSnackBar
  ) {}

  POKEMON_ACTIONS_SUCCESS = [
    PokemonActions.addSuccess,
    PokemonActions.updateSuccess,
    PokemonActions.removeSuccess,
    PokemonActions.loadPokemonSuccess
  ];

  POKEMON_ACTIONS_FAILED = [
    PokemonActions.addFailed,
    PokemonActions.updateFailed,
    PokemonActions.removeFailed,
    PokemonActions.loadPokemonFailed
  ];

  loadAllPokemon$ = createEffect(() =>
    this.actions$.pipe(
      ofType(PokemonActions.loadPokemon),
      switchMap(() =>
        this.pokemonService.getAll().pipe(
          map(pokemons => PokemonActions.loadPokemonSuccess({ pokemons })),
          catchError(message =>
            of(PokemonActions.loadPokemonFailed({ message }))
          )
        )
      )
    )
  );

  addPokemon$ = createEffect(() =>
    this.actions$.pipe(
      ofType(PokemonActions.add),
      switchMap((action: any) =>
        this.pokemonService.add(action.pokemon).pipe(
          map((pokemon: Pokemon) => PokemonActions.addSuccess({ pokemon })),
          catchError(message => of(PokemonActions.addFailed({ message })))
        )
      )
    )
  );

  deletePokemon$ = createEffect(() =>
    this.actions$.pipe(
      ofType(PokemonActions.remove),
      switchMap(({ id }) =>
        this.pokemonService.delete(id).pipe(
          map(() => PokemonActions.removeSuccess({ id })),
          catchError(message => of(PokemonActions.removeFailed({ message })))
        )
      )
    )
  );

  updatePokemon$ = createEffect(() =>
    this.actions$.pipe(
      ofType(PokemonActions.update),
      switchMap(({ pokemon }) =>
        this.pokemonService.update(pokemon).pipe(
          map(() => PokemonActions.updateSuccess({ pokemon })),
          catchError(message => of(PokemonActions.updateFailed(message)))
        )
      )
    )
  );

  successNotification$ = createEffect(
    () =>
      this.actions$.pipe(
        ofType(...this.POKEMON_ACTIONS_SUCCESS),
        tap(() =>
          this.snackBar.open('SUCCESS', 'Operation success', {
            duration: 2000
          })
        )
      ),
    { dispatch: false }
  );

  failedNotification$ = createEffect(
    () =>
      this.actions$.pipe(
        ofType(...this.POKEMON_ACTIONS_FAILED),
        tap(() =>
          this.snackBar.open('FAILED', 'Operation failed', {
            duration: 2000
          })
        )
      ),
    { dispatch: false }
  );
}
```

Note that the previously used `dispatch: false` parameter passed to each effect is now the second parameter passed to the `createEffect` method.  Remember that the option `{ dispatch: false }` is used for effects that don't dispatch new Actions, adding this option also removes the restriction of effect having to return an `Observable<Action>`.

# Reducers
The new `createReducer` method allows to create a reducer without a `switch` statement. There is a new `on` method to make a distinction between the action types, and it returns a new state reference. Another interesting fact is not needing to handle a default case for unhandled actions in the reducer.

Therefore, the *before* and *after* `pokemon.reducers.ts` are the following ones:

**before**
```typescript
import { PokemonActionTypes, PokemonActions } from './pokemon.actions';
import { PokemonState, pokemonAdapter } from './pokemon.adapter';

export function pokemonInitialState(): PokemonState {
  return pokemonAdapter.getInitialState();
}

export function pokemonReducer(
  state: PokemonState = pokemonInitialState(),
  action: PokemonActions
): PokemonState {
  switch (action.type) {
    case PokemonActionTypes.LOAD_POKEMONS_SUCCESS:
      return pokemonAdapter.addAll(action.payload, state);

    case PokemonActionTypes.ADD_SUCCESS:
      return pokemonAdapter.addOne(action.pokemon, state);

    case PokemonActionTypes.DELETE_SUCCESS:
      return pokemonAdapter.removeOne(action.id, state);

    case PokemonActionTypes.UPDATE_SUCCESS:
      const { id } = action.pokemon;
      return pokemonAdapter.updateOne(
        {
          id,
          changes: action.pokemon
        },
        state
      );

    default:
      return state;
  }
}
```

**after**
```typescript
import { Action, createReducer, on } from '@ngrx/store';
import { PokemonState, pokemonAdapter } from './pokemon.adapter';

import { actions as PokemonActions } from './pokemon.actions';

export function pokemonInitialState(): PokemonState {
  return pokemonAdapter.getInitialState();
}

const pokemonReducer = createReducer(
  pokemonInitialState(),
  on(PokemonActions.loadPokemonSuccess, (state, { pokemons }) =>
    pokemonAdapter.addAll(pokemons, state)
  ),
  on(PokemonActions.addSuccess, (state, { pokemon }) =>
    pokemonAdapter.addOne(pokemon, state)
  ),
  on(PokemonActions.removeSuccess, (state, { id }) =>
    pokemonAdapter.removeOne(id, state)
  ),
  on(PokemonActions.updateSuccess, (state, { pokemon }) =>
    pokemonAdapter.updateOne({ id: pokemon.id, changes: pokemon }, state)
  )
);

export function reducer(state: PokemonState | undefined, action: Action) {
  return pokemonReducer(state, action);
}
```

Note that the `createReducer` method receives a list of parameters: 
the first parameter is the initial State and the second parameter is a list of `on` methods. In the `on` method the first parameter is the related action. In my case, I have maintained the actions `enum` because I like the data structure. You, of course, can export the actions directly without the use of an enum. The second parameter of the `on` method is a callback in which the `state` and `payload` are received. After that, we can use the powerful `EntityAdapter` to perform the most common operations.



# Conclusions
In this post we have refactored our Pokédex by using the `@ngrx/entity` package's `create*` functions. The use of the create* functions will reduce unnecessary complexity in the management of the state of our application. Futhermore, the adapter is used to perform the most common operations (CRUD). 
    
Therefore, in this post we have covered the following topics:
    
    
- Automate the creation of state, since it is very repetitive, by using @ngrx/entity.
- Automate the creation of effects, actions and simplify the reduce function by using `@ngrx/entity`.
    
The following posts in this series will cover interesting topics such as:

- Facade pattern will be used through the `@ngrx/data` package.
- Testing the application's state.

The most important part of this post is the concepts shown, and not the technique or library used. Therefore, this post should be taken as a guide for those who start to have large Angular applications and require applying architectural principles.


# More, More and More...
* [Announing NgRx 8](https://medium.com/ngrx/announcing-ngrx-version-8-ngrx-data-create-functions-runtime-checks-and-mock-selectors-a44fac112627)
* [Angular Architecture Best Practices](https://angular-academy.com/angular-architecture-best-practices/)
* [Angular Architecture - ng-conf](https://www.ng-conf.org/2019/angular-architecture-specific-layers/)
* [Angular Architecture (official docs)](https://angular.io/guide/architecture)
* [NGRX](https://ngrx.io/)
* [RxJS](https://rxjs-dev.firebaseapp.com/)
* [Facade Pattern](https://www.carloscaballero.io/design-patterns-facade/)

The *GitHub branch* of this post is [https://github.com/Caballerog/ngrx-pokedex/tree/ngrx-part3](https://github.com/Caballerog/ngrx-pokedex/tree/ngrx-part3)