Store NgRx

Sophie Andriamahenintsoa
4 min readDec 29, 2021
ngrx store, redux rxjs, angular redux

Store

A `store` is a state container, wich holds application’state. It’s built on a single, immutable data structure.

As picture show below, store has 3 main concepts:

Redux ngrx store

Action:

An action defines the intention. It must have a type for identification, and can contain payload if necessary.

Reducer:

  • A reducer should be a pure function
  • A reducer receives as parameter the previous state and the latest action dispatched, to provide a new stat
  • Handle the state transitions in an immutable way

Effects:

To reduce state based on external interactions such as fetching data from remote server, local store/session storage, web socket messages, Effects use streams to provide new sources of actions.

ngrx lifecycle effetcs
  • Effects isolate side effects from components, allowing for more pure components that select state and dispatch actions.
  • Effects are long-running services that listen to an observable of every action dispatched from the Store.
  • Effects filter those actions based on the type of action they are interested in. This is done by using an operator.
  • Effects perform tasks, which are synchronous or asynchronous and return a new action

Realization’s steps:

  • Installation

Installing with npm:

npm install @ngrx/store --save

Installing with yarn:

yarn add @ngrx/store

If your project is using the Angular CLI 6+ then you can install the Store to your project with the following ng add command

ng add @ngrx/store@latest
  • If you want to use effects, you need to install it.

Installing with npm or yarn

npm install @ngrx/effects --saveyarn add @ngrx/effects

If your project is using the Angular CLI 6+ then you can install the Effects to your project with the following ng add command.

ng add @ngrx/effects@latest
  • Folder structure:

Inside a module, you can have a folder `store` with the following structure:

  • Architecture:

Example of Action written:

export enum TodoListActionsEnum {
setNewItem = '[Todo list] Set new todo list item',
}

export interface NewItemActionType {
id: number;
cName: string;
}

export const setNewItem = createAction(
TodoListActionsEnum.setNewItem,
props<NewItemActionType>()
);

There are several ways to define an action, but in our case we define an action with the function createAction, and the available type of the action are defined inside an `enum`.

Rule for action type:

The action type is a string, you can pass any string you want ; but to be more clear about intention, we have our own template to define an action type:

[Scope or feature name][intention (create, update, etc.)] a little description

Use the action creator to return the Action when dispatching.

Example of Reducer written:

Steps:

  • Set initial state value (defaults)wich will be called when current state is undefined.
export const initialState: TodoListState = {
items: [],
}
  • Create reducer function:

Create a reducer function that handles the actions for managing the state using the createReducer function.

const onSetNewItem = (state: TodoListState, item: NewItemActionType) => ({
...state,
items: state.items.concat(item),
});

const todoListReducer = createReducer(
initialState,
on(TodoListAction.setNewItem, onSetNewItem),
);

export function reducer(
state: TodoListState = initialState,
action: Action
): TodoListState {
return todoListReducer(state, action);
}
  • Register Reducer to root:

use StoreModule.forRoot() to register the global Store within your application.

Example to register Store on app.module.ts


imports : [
...,
StoreModule.forRoot({todoListData: reducer}),
StoreDevtoolsModule.instrument({maxAge: 25}),
]

In component file:

addNewItem(): void {
this.store.dispatch(setNewItem({id: this.id, cName: this.name}));
}

The setNewItem action creator receives anj object of id and name and returns a PJO with a type property ‘[Todo list] Set new todo list item’, with id and cName as additional props

Example of Effects written:

@Injectable()
export class TodoListEffects {
loadTodoList$ = createEffect(() => this.actions$.pipe(
ofType(TodoListActions.fetchTodoListItems),
switchMap(() =>
this.userTodoService.list().pipe(
map( (list: TodoListApiType[]) => {
return TodoListActions.fetchedTodoListItems({items: list})
})
))
));

constructor(
private actions$: Actions,
...
) {}
}

ofType represents the types of actions (based on createAction function). This operator takes up 5 arguments with proper type inference.

Registering root effects:

After you’ve written your Effects class, you must register it so the effects start running. Add EffectsModule.forRoot() method with an array to your app-module.

imports: [
...,
StoreModule.forRoot({ todoListData: reducer}),
EffectsModule.forRoot([TodoListEffects]),
...
]

That’s it, we are now managing states with NgRx.

I appreciate the time you take to read my stories. If you you like it, don’t hesitate to give a 👏 give don’t hesitate to follow ✍ https://medium.com/@sophieelsa

--

--

Sophie Andriamahenintsoa

Front-end dev, focused on UI/UX(+responsive design, accessibility), JS/TS and their frameworks, animations