Reactive State management in the angular - NgRx Store, actions, selectors
Tags: angular, typescript, all, ngrx
Published: 2020-09-15 22:07:34

---
title: Reactive State management in the angular - NgRx Store, actions, selectors
published: true
date: 2020-09-15 00:00:00 UTC
tags: angular,typescript,all,NgRx
canonical_url: http://www.initgrep.com/posts/javascript/angular/state-management-in-angualar-using-ngrx
---

NgRx framework helps to build reactive angular applications.

## Basic Concepts

`NgRx store` provides reactive state management for the angular application. NgRx store is the redux implementation developed specifically for angular applications and provides RxJS observable API.

`state` is an immutable data structure that is a single source of truth for the whole application.

`NgRx Actions` represent the unique events in the application which may be used to perform state transition or trigger side-effects.

`NgRx Reducers `are pure functions that react to `Actions `to perform state transitions.

`NgRx Selectors `are pure functions that select, derive, or compose a slice of the state.

`NgRx Effects` allow the isolation of side-effects.

 

## Prerequisites -
- you have a fair understanding of the angular framework.
- You have a basic understanding of redux architecture.
- you have a fair knowledge of `RxJs` Observable API and various operators.

#### Table of contents

- **Installation**
- **State**
  - Design the State
  - Initialize the State
- **NgRx Actions**
- **NgRx Reducer**
  - createReducer function
  - Create ActionReducerMap
  - Register the State
- **NgRx selectors**
  - Selectors
  - createSelector function
  - String selectors.

 

## Installation

If you already have an angular app, you can directly go to **step - 4**

```
# 1) install angular cli
npm install -g @angular/cli

# 2) create a demo app
ng new ngrx-angular-demo

# 3) navigate to demo app
cd ngrx-angular-demo

# 4) install ngrx store
ng add @ngrx/store@latest

# 5) run angular in dev mode
ng serve

```

 

**To begin with** , let us have a look at an example file structure. A structure like this would be helpful to split up each feature of `NgRx `state management in your app. I usually replicate the same structure in each feature module.

```

    ──store
        |_ app.actions.ts
        |_ app.effects.ts
        |_ app.reducer.ts
        |_ app.selectors.ts

```

- `app.actions.ts` file will contain the `NgRX actions`
- `app.effects.ts `file will contain the `NgRx effects`.
- `app.reducer.ts` file will contain the `State` design and its initialization. it will also contain a reducer function.
- `app.selectors.ts` will contain the `NgRx selectors`.

Here is the complete [project setup](https://github.com/initgrep-post-demos/ngrx-demo/tree/master/src/app/store).

## State

The state represents an immutable object that contains the state of an application. It is read-only, so every state transition will return a new state rather than modifying the existing state. As the application grows, each feature should contain a separate state which are part of the global app state. As such, the application state contains one or more feature states.

The state is similar to `Javascript` objects. It contains the feature states as the `key-value` pairs _where the `key` represents a feature state and the `value ` is the feature state object.

The state related to a feature module is referred to as `feature state`.

```
interface State{
    feature_1: FeatureOneState,
    feature_2: FeatureTwoState,
    feature_3: FeatureThreeState
}

```

### Design the State

Let’s assume, our angular application has many feature modules. One of the feature modules is responsible for user’s profile. The `profile `module is responsible for rendering the list of `users `and the related `posts `.

To design the state, we can assume that the state required for the profile module should contain **List of users** and **List of posts**.

Let’s call the profile state as `ProfileFeatureState`.

```
/** User modal */
export interface User {

  id: number;
  email: string;
  first_name: string;
  last_name: string;
  avatar: string;
}

/ **post modal** /
export interface Post {
  id: number;
  userId: number;
  title: string;
  body: string;
}

/ **the modals should ideally be in their own ts file** /

export interface ProfileFeatureState {
  users: User[];
  posts: Post[];
}

```

We defined the type for `User `and `Post` and also created an interface for `ProfileFeatureState`.

Finally, we would add `ProfileFeatureState` to the applications root state -`AppState`. The `profile` key represents the `profileFeatureState`.

```
interface AppState{    
    profile: UserFeatureState,    
//..other features here
}

```

### Initialize the State

Initially, the state of the application is `null `since there would be no data. As such, both the `users array` and `posts array` would be initialized to `null`.

```
export const initialProfileFeatureState: ProfileFeatureState = {
  users: null,
  addresses: null
};

```

At this point, the `app.reducer.ts` file should look like -

```
/*app.reducer.ts*/

/** User modal */
export interface User {
  id: number;
  email: string;
  first_name: string;
  last_name: string;
  avatar: string;
}

/** Post Modal */

export interface Post {
  id: number;
  userId: number;
  title: string;
  body: string;
}

export interface ProfileFeatureState {
  users: User[];
  addresses: Address[];
}

export const initialProfileFeatureState: ProfileFeatureState = {
  users: null,
  addresses: null
};

export interface AppState {
  profile: ProfileFeatureState;
}

```


## Actions:

NgRx Actions represent events in the application. They may trigger a state transition or trigger a side-effect in the `NgRx Effect` services.

```
interface Action{
    type:string
    //optional metadata properties
}

```

The `Action `interface contains a property called `Type`. The `Type `property **identifies** the action. Actions can also contain optional `metadata`.

`createAction `function is used to create the actions and it returns an [ActionCreator](https://ngrx.io/api/store/ActionCreator) function. `ActionCreator` function when called returns an action of type `TypedAction`. Optionally, we can also supply additional metadata using [props](https://ngrx.io/api/store/props) function.

Let’s go ahead and create an action to add users to `ProfileFeatureState`.

```
export const addUsers = createAction(
 '[profile] add users',
 props<{ users: User[] }>()
);

```

Notice the type of `addUsers` action as `[profile] add users`. The `[profile]` represents the source of action. Also, the props contain the array of users as the metadata.

Similarly, we can create an action for adding posts to the feature state.

```
//file: app.actions.ts

export const addPosts = createAction(
  '[profile] add posts',
  props<{ posts: Post[] }>()
);

```

**`addUsers`** action is dispatched to indicate that the users should be added to the state. It will also contain `user[]` as metadata.

_Similarly the Actions related to posts are dispatched_

> Actions represent the events and not the commands or operations. A single command or operation may generate many types of Actions. For example, An operation that creates a new user would at least generate Actions for _success_ and _failure_ such as `[profile] user created` or `[profile] user creation failed`.



## NgRx Reducer -

Reducers are [**pure functions**](https://en.wikipedia.org/wiki/Pure_function) which perform transitions from one state to another state based on the latest action dispatched. The reducer functions do not modify the existing state, rather it returns a new state for every state transition. Hence all the reducer functions perform immutable operations.

### CreateReducer

**NgRx** provides a [createReducer](https://ngrx.io/api/store/createReducer) function to create reducers. It takes `initialState` as the first param and `any` number of `on` functions. The `on` function provide association between actions and the state changes.

_When an action is dispatched, all the reducers receive the action. The `on` function mapping determines whether the reducer should handle the action._

`createReducer` function returns an [ActionReducer](https://ngrx.io/api/store/ActionReducer) function . ActionReducer function takes an [Action](https://ngrx.io/api/store/Action) and a [State](https://ngrx.io/api/store/State) as input, and returns a new computed State.

Let’s go ahead a create reducer that handles transitions for `ProfileFeatureState`.

```
import * as AppActions from './app.actions';

const theProfFeatureReducer = createReducer(
  initialProfileFeatureState,
  on(AppActions.addUsers, (state, { users }) => ({
    ...state,
    users: [...users]
  })),
  on(AppActions.addPosts, (state, { posts }) => ({
    ...state,
    posts: [...posts]
  })),

);

```

`createReducer` function maps many actions and returns an `ActionReducer` function.

`addUsers` action is **mapped** to a _function that creates a new `User` array and returns a newly computed state_. Similarly the `addPosts` action is mapped.

> _The […] `spread operator` copies the properties of the object and returns a new object. It only performs the shallow copying and does not copy the nested structures. You should always consider a better alternative if you are dealing with a state that contains nested data structures. Libraries like **lodash** provide methods to clone nested structures._

### Create ActionReducerMap

`ActionReducerMap` provides the mapping as `key-value` pairs where the `key` represents the feature name as a string and the `value` is the `ActionReducer function` returned by `createReducer` function.

In our case, the `ActionReducerMap` will contain `profile` as a key and `value` as `theProfFeatureReducer`.

```
/**The profileFeatureReducer function is necessary as function calls are not supported in the View Engine AOT compiler. It is no longer required if you use the default Ivy AOT compiler (or JIT)**/

function profileFeatureReducer
(state: ProfileFeatureState = initialState, action: Action) {
  return theProfFeatureReducer(state, action);
}

/ **AppActionReducer Map** /
export const AppActionReducerMap: ActionReducerMap<AppState> = {
  profile: profileFeatureReducer
  // ... other feature go here

};

```

_It is not necessary to create an `ActionReducerMap`. You can directly provide the mapping in `StoreModule.forRoot({key: ActionReducer})`while registering the reducer in app.module.ts. You can also separately register the feature state in the feature module. I prefer creating the `ActionReducerMap `separately as it provides a better type checking in Typescript._

At this point, our `app.reducer.ts` file should look like :

```
/ **app.reducer.ts** /
export interface ProfileFeatureState {
  users: User[];
  posts: Post[];
}

export const initialProfileFeatureState: ProfileFeatureState = {
  users: null,
  posts: null
};

export interface AppState {
  profile: ProfileFeatureState;
}

const theProfFeatureReducer = createReducer(
  initialProfileFeatureState,
  on(AppActions.addUsers, (state, { users }) => ({
    ...state,
    users: [...users]
  })),
  on(AppActions.addPosts, (state, { posts }) => ({
    ...state,
    posts: [...posts]
  }))
);

function profileFeatureReducer(state: ProfileFeatureState = initialProfileFeatureState, action: Action) {
  return theProfFeatureReducer(state, action);
}

export const AppActionReducerMap: ActionReducerMap<AppState> = {
  profile: profileFeatureReducer
};

```

 

#### Register the State

Once the reducer is created, It should be registered in the Module . The state can be registered using one of the two options:

**Register Root state**

To register the global store in the application

```
StoreModule.forRoot({ AppActionReducerMap })

```

`StoreModule.forRoot()` takes `ActionReducerMap` as an argument. The map contains `key` and `ActionReducer` Object returned by `createReducer` function.

**Register each feature state separately -**

Feature states are similar to root states but they represent the state of specific features of an application. Typically, each feature should be registed in its own module.

```
StoreModule.forFeature({ profile: profileFeatureReducer })

```
If you have come this far. You might also want to read about NgRx Selectors.
- How to create NgRx Selectors
- How to use createSelector function to compose selectors with - single or multiple slices of state
- How to use a projector function to return only a part within the slice of state.

_NgRx selectors are used to select a slice of state. I have a detailed post about it **[here](https://www.initgrep.com/posts/javascript/angular/state-management-in-angualar-using-ngrx)**_