---
title: Bitovi Academy - Create a Reducer
description: Learn how to create an NgRx Reducer.
---

- ![AI implementation](https://www.bitovi.com/hubfs/AIConsultingIcon.svg)
  
  [AI implementation](https://www.bitovi.com/services/ai-consulting?hsLang=en-us)
- ![Systems engineering](https://www.bitovi.com/hubfs/icon%20-%20backend.svg)
  
  [Systems engineering](https://www.bitovi.com/services/systems-engineering-consulting?hsLang=en-us)
- ![Project management](https://www.bitovi.com/hubfs/icon%20-%20PM.svg)
  
  [Project management](https://www.bitovi.com/services/agile-project-management-consulting?hsLang=en-us)
- ![Product design](https://www.bitovi.com/hubfs/icon%20-%20design.svg)
  
  [Product design](https://www.bitovi.com/services/product-design-consulting?hsLang=en-us)
- ![Frontend development](https://www.bitovi.com/hubfs/icon%20-%20frontend.svg)
  
  [Frontend development](https://www.bitovi.com/services/frontend-development-consulting?hsLang=en-us)
- [View more
  
  →
  
  ](https://www.bitovi.com/digital-consulting-services?hsLang=en-us)

We're Experts in...

- [JavaScript](https://www.bitovi.com/services/frontend/javascript-consulting?hsLang=en-us)
- [AI training](https://www.bitovi.com/ai-training-for-software-engineers?hsLang=en-us)
- [Angular](https://www.bitovi.com/services/frontend/angular-consulting?hsLang=en-us)
- [Design Systems](https://www.bitovi.com/services/axure-figma-migration?hsLang=en-us)
- [React](https://www.bitovi.com/services/frontend/react-consulting?hsLang=en-us)
- [Temporal](https://www.bitovi.com/services/backend/temporal-consulting?hsLang=en-us)
- [React Native](https://www.bitovi.com/services/frontend/react-consulting/react-native?hsLang=en-us)
- [Node.js](https://www.bitovi.com/services/backend/nodejs-consulting-1?hsLang=en-us)

Showcase

![Yum! Brands](https://www.bitovi.com/hubfs/yum-showcase-link-1.png)

[View case study](https://www.bitovi.com/en/bitovi-yum-case-study?hsLang=en-us)

More Projects

- [![Levi's](https://www.bitovi.com/hubfs/levis.svg)](https://www.bitovi.com/web-application-consulting-work/levis-ecommerce-responsive-redesign?hsLang=en-us)
- [![Christie's International Real Estate](https://www.bitovi.com/hubfs/christies.svg)](https://design.bitovi.com/christies)
- [![BAFS](https://www.bitovi.com/hubfs/bafs.svg)](https://www.bitovi.com/ux-design-consulting/ux-case-studies/bafs-ppp?hsLang=en-us)
- [View more
  
  →
  
  ](https://www.bitovi.com/our-software-consulting-work?hsLang=en-us)

Open Source Tools

We build powerful tools and open source them to support the community.

[See what we've built →](https://www.bitovi.com/open-source?hsLang=en-us)

- [![Blog](https://www.bitovi.com/hubfs/icon%20-%20blog.svg)
  
  BlogWe post about perfecting software delivery
  
  ](https://bitovi.com/blog)
- [![Partnerships](https://www.bitovi.com/hubfs/Handshake-1.svg)
  
  PartnershipsLearn about Bitovi's technology partners
  
  ](https://www.bitovi.com/partnerships?hsLang=en-us)
- [![Academy](https://www.bitovi.com/hubfs/limbo/icons/icon-academy.svg)
  
  AcademyFree courses to build delivery skills
  
  ](https://www.bitovi.com/academy/?hsLang=en-us)
- [![Open source tools](https://www.bitovi.com/hubfs/icon%20-%20open%20source.svg)
  
  Open source toolsUse our tools or contribute to our open source mission.
  
  ](https://www.bitovi.com/open-source?hsLang=en-us)

Let's Connect

- [![Discord](https://www.bitovi.com/hubfs/DiscordLogo.svg)
  
  Discord
  
  ](https://discord.gg/J7ejFsZnJ4)
- [![LinkedIn](https://www.bitovi.com/hubfs/LinkedinLogo.svg)
  
  LinkedIn
  
  ](https://www.linkedin.com/company/bitovi/)
- [![GitHub](https://www.bitovi.com/hubfs/GithubLogo.svg)
  
  GitHub
  
  ](https://github.com/bitovi/)

![Eggbot](https://www.bitovi.com/hubfs/build_assets/bitovi-limbo-cms-react/338/js_client_assets/assets/eggbot-LTGhdSGL.png)

Name *

Work Email *

Phone

What's your project?

Send

### Contact Us

(312) 620-0386contact@bitovi.com

- [ Advanced JavaScript ](https://www.bitovi.com/academy/learn-advanced-javascript.html?hsLang=en-us)
- [ DOM and jQuery ](https://www.bitovi.com/academy/learn-dom-jquery.html?hsLang=en-us)
- [ Debug JavaScript ](https://www.bitovi.com/academy/learn-to-debug-javascript.html?hsLang=en-us)
- [ Learn TypeScript ](https://www.bitovi.com/academy/learn-typescript.html?hsLang=en-us)
- [ Learn React Native ](https://www.bitovi.com/academy/learn-react-native.html?hsLang=en-us)
- [ Learn Web Components ](https://www.bitovi.com/academy/learn-web-components.html?hsLang=en-us)
- [ Agile Program Management With Jira ](https://www.bitovi.com/academy/learn-agile-program-management-with-jira.html?hsLang=en-us)
- [ Learn RxJS ](https://www.bitovi.com/academy/learn-rxjs.html?hsLang=en-us)
- [ Giving a Training ](https://www.bitovi.com/academy/training.html?hsLang=en-us)
- [ Learn Technology Consulting ](https://www.bitovi.com/academy/learn-technology-consulting.html?hsLang=en-us)
- [ Learn React ](https://www.bitovi.com/academy/learn-react.html?hsLang=en-us)
- [ Learn NgRx ](https://www.bitovi.com/academy/learn-ngrx.html?hsLang=en-us) 
    - [ Why NgRx ](https://www.bitovi.com/academy/learn-ngrx/why-ngrx.html?hsLang=en-us)
    - [ Getting Started ](https://www.bitovi.com/academy/learn-ngrx/getting-started.html?hsLang=en-us)
    - [ Installing NgRx ](https://www.bitovi.com/academy/learn-ngrx/ngrx-init.html?hsLang=en-us)
    - [ Creating Actions ](https://www.bitovi.com/academy/learn-ngrx/create-actions.html?hsLang=en-us)
    - [ Dispatching Actions ](https://www.bitovi.com/academy/learn-ngrx/dispatch-actions.html?hsLang=en-us)
    - [ Testing Actions ](https://www.bitovi.com/academy/learn-ngrx/test-actions.html?hsLang=en-us)
    - [ Create an API Effect ](https://www.bitovi.com/academy/learn-ngrx/create-api-effects.html?hsLang=en-us)
    - [ Testing API Effects ](https://www.bitovi.com/academy/learn-ngrx/test-api-effects.html?hsLang=en-us)
    - [ Creating Redirect Effects ](https://www.bitovi.com/academy/learn-ngrx/create-redirect-effects.html?hsLang=en-us)
    - [ Testing Redirect Effects ](https://www.bitovi.com/academy/learn-ngrx/test-redirect-effects.html?hsLang=en-us)
    - [ Create a Reducer ](https://www.bitovi.com/academy/learn-ngrx/create-reducer.html?hsLang=en-us)
    - [ Testing Reducers ](https://www.bitovi.com/academy/learn-ngrx/test-reducer.html?hsLang=en-us)
    - [ Creating Selectors ](https://www.bitovi.com/academy/learn-ngrx/create-selectors.html?hsLang=en-us)
    - [ Testing Selectors ](https://www.bitovi.com/academy/learn-ngrx/test-selectors.html?hsLang=en-us)
    - [ Using Selectors ](https://www.bitovi.com/academy/learn-ngrx/use-selectors.html?hsLang=en-us)
    - [ Testing Selector Use ](https://www.bitovi.com/academy/learn-ngrx/test-used-selectors.html?hsLang=en-us)
- [ Learn Graphql ](https://www.bitovi.com/academy/learn-graphql.html?hsLang=en-us)
- [ Learn Docker ](https://www.bitovi.com/academy/learn-docker.html?hsLang=en-us)
- [ Learn CanJS ](https://www.bitovi.com/academy/learn-canjs.html?hsLang=en-us)
- [ Learn Angular ](https://www.bitovi.com/academy/learn-angular.html?hsLang=en-us)
- [ Advanced TypeScript ](https://www.bitovi.com/academy/advanced-typescript.html?hsLang=en-us)

[View More Courses](https://www.bitovi.com/academy/#courses) [ ]

# Create a Reducer `page`

Learn how to create an NgRx Reducer.

> **Quick Start**: You can checkout [this branch](https://github.com/bitovi/angular-ngrx-chat/tree/test-redirect-effects) to get your codebase ready to work on this section.

## Overview

1. Define Login State shape.
2. Set Login initial state.
3. Update Reducer function to include handler for `LoginActions.loginSuccess` Action to update Login State.
4. Update Reducer function to include handler for `LoginActions.logoutSuccess` Action to reset Login State.

## Problem 1: Define Login State Shape

Update the Login State shape by adding `userId`, `username`, and `token` properties to its interface definition. Each property should have type `string | null`.

## P1: What you need to know

Now that we have all of our Actions prepared to dispatch whenever we need, we will update the Login State. Typically a Reducer is updated with 3 steps:

1. Define or update `Store` interface to have an [expected shape](https://ngrx.io/guide/store/reducers#defining-the-state-shape) after Reducer updates state.
2. Set or update value to [state’s initial value](https://ngrx.io/guide/store/reducers#setting-the-initial-state) to satisfy new `Store` interface definition.
3. [Add or update handler(s)](https://ngrx.io/guide/store/reducers#creating-the-reducer-function) used to define Reducer function.

To prepare this, we need to update the Login Feature `State` interface found at `src/app/store/login/login.reducer.ts`. Here is an example of how to add properties to an interface:

```
// Note: This example code is not part of our application repo or solution

export interface Contact {
    emailAddress: string | null;
    fullName: string | null;
}

```

## P1: Solution

src/app/store/login/login.reducer.ts

```
// src/app/store/login/login.reducer.ts

import { createReducer } from '@ngrx/store';

export const loginFeatureKey = 'login';

export interface State {
  userId: string | null;
  username: string | null;
  token: string | null;
}

export interface LoginPartialState {
  [loginFeatureKey]: State;
}

export const initialState: State = {

};

export const reducer = createReducer(
  initialState
);

```

## Problem 2: Set Initial Value For Login State

Set initial state for Login State. Each member of the Login State should start with `null` as its value.

## P2: What you need to know

Now that we have updated the Login State’s shape by updating the `State` interface, we need to update its initial shape. By default, we will set each member to `null`. Here is an example of doing that:

```
export const initialValue: Contact = {
    emailAddress: null;
    fullName: null;
}

```

## P2: Solution

src/app/store/login/login.reducer.ts

```
// src/app/store/login/login.reducer.ts

import { createReducer } from '@ngrx/store';

export const loginFeatureKey = 'login';

export interface State {
  userId: string | null;
  username: string | null;
  token: string | null;
}

export interface LoginPartialState {
  [loginFeatureKey]: State;
}

export const initialState: State = {
  userId: null,
  username: null,
  token: null,
};

export const reducer = createReducer(
  initialState
);

```

## Problem 3: Update Login State With Login Information On Login

Login Reducer should include an `on()` handler that updates Login State with `userId`, `username` and `token` whenever `LoginActions.loginSuccess` Action is dispatched.

## P3: What you need to know

We can [create NgRx Reducers](https://ngrx.io/guide/store/reducers#creating-the-reducer-function) using the [`createReducer()`](https://ngrx.io/api/store/createReducer#description) helper function.

The first argument for `createReducer()` sets the initial value of your State. Then every argument after should be an [`on()` handler function calls](https://ngrx.io/api/store/on).

When writing an `on()` handler, there are 2 arguments that we need to provide:

1. The Action that this `on()` handler is reacting to.
2. A [**pure function**](https://en.wikipedia.org/wiki/Pure_function) that takes in 2 arguments: `state` and `action`. This function should always return a new state that will replace the previous state.

```
// Note: This example code is not part of our application repo or solution

import { createReducer, on } from '@ngrx/store';
import * as CounterActions from './counter.actions';

export const scoreboardReducer = createReducer(
  initialState,// Initial feature state
  on(CounterActions.set, (state, action) => ({ ...state, count: action.count })),// Set counter
  on(CounterActions.increment, state => ({ ...state, count: state.count + 1 })),// Increment counter
  // ...
);

```

## P3: Solution

src/app/store/login/login.reducer.ts

```
// src/app/store/login/login.reducer.ts

import { createReducer, on } from '@ngrx/store';
import * as LoginActions from './login.actions';

export const loginFeatureKey = 'login';

export interface State {
  userId: string | null;
  username: string | null;
  token: string | null;
}

export interface LoginPartialState {
  [loginFeatureKey]: State;
}

export const initialState: State = {
  userId: null,
  username: null,
  token: null,
};

export const reducer = createReducer(
  initialState,
  on(
    LoginActions.loginSuccess,
    (state, { userId, username, token }): State => ({
      ...state,
      userId,
      username,
      token,
    })
  )
);

```

## Problem 4: Reset Login State On Logout

Login Reducer should include an `on()` handler that resets Login State back to `initialState` whenever `LoginActions.logoutSuccess` Action is dispatched.

## P4: What you need to know

A common requirement is to reset state. One approach might look like this:

```
// Note: This example code is not part of our application repo or solution

import { createReducer, on } from '@ngrx/store';
import * as CounterActions from './counter.actions';

export const scoreboardReducer = createReducer(
  initialState,// Initial feature state
  on(CounterActions.set, (state, action) => ({ ...state, count: action.count })),// Set counter
  on(CounterActions.increment, state => ({ ...state, count: state.count + 1 })),// Increment counter
  on(CounterActions.reset, (state) => ({ ...state, count: 0 })),// Reset counter
  // ...
);

```

But there is nothing wrong with reusing the `initialState` constant:

```
// Note: This example code is not part of our application repo or solution

import { createReducer, on } from '@ngrx/store';
import * as CounterActions from './counter.actions';

export const scoreboardReducer = createReducer(
  initialState,// Initial feature state
  on(CounterActions.set, (state, action) => ({ ...state, count: action.count })),// Set counter
  on(CounterActions.increment, state => ({ ...state, count: state.count + 1 })),// Increment counter
  on(CounterActions.reset, () => ({ ...initialState })),// Reset counter
  // ...
);

```

Both solutions are fine, but it is likely better to reuse `initialState` to future-proof the Reducer for future requirements.

## P4: Solution

src/app/store/login/login.reducer.ts

```
// src/app/store/login/login.reducer.ts

import { createReducer, on } from '@ngrx/store';
import * as LoginActions from './login.actions';

export const loginFeatureKey = 'login';

export interface State {
  userId: string | null;
  username: string | null;
  token: string | null;
}

export interface LoginPartialState {
  [loginFeatureKey]: State;
}

export const initialState: State = {
  userId: null,
  username: null,
  token: null,
};

export const reducer = createReducer(
  initialState,
  on(
    LoginActions.loginSuccess,
    (state, { userId, username, token }): State => ({
      ...state,
      userId,
      username,
      token,
    })
  ),
  on(LoginActions.logoutSuccess, (): State => ({ ...initialState }))
);

```

> **Wrap-up**: By the end of this section, your code should match [this branch](https://github.com/bitovi/angular-ngrx-chat/tree/create-reducer). You can also compare the [code changes for our solution to this section](https://github.com/bitovi/angular-ngrx-chat/compare/test-redirect-effects...create-reducer) on GitHub or you can use the following command in your terminal:

```
git diff origin/create-reducer
```

###### On this page...

###### Get help

If you need [help](https://discord.gg/J7ejFsZnJ4) with an exercise, please reach out to us on [Discord](https://discord.gg/J7ejFsZnJ4)

If you find a bug, please [create an issue](https://github.com/bitovi/academy/issues/new) or email [contact@bitovi.com](mailto:contact@bitovi.com?Subject=Training%20Suggestion)

## Join the Bitovi Newsletter

 Do you want to receive updates about new Bitovi Academy courses, Bitovi open source projects, and dev community news? If so, please provide your email. We won’t spam you or give it away for any reason!  
*By providing your email you agree to receive communications from Bitovi*

![](https://bitovi.github.io/academy/static/img/close.svg)

```json
{
     "@context": "http://schema.org",
     "@type": "Organization",
     "mainEntityOfPage":{
          "@type":"WebPage",
          "@id":"https://www.bitovi.com/academy/learn-ngrx/create-reducer.html",
          "description": "Learn how to create an NgRx Reducer. 
"
     },
     "url": "http://bitovi.com",
     "logo": "https://www.bitovi.com/hubfs/bitovi-logo-23-1.svg",
     "image": "https://www.bitovi.com/hubfs/bitovi-logo-x2.png",
     "name": "Bitovi Web App Consulting",
     "alternateName": "Bitovi",
      "naics": "541511",
      "description": "Bitovi is a UX, UI design and front-end JavaScript development consulting company",
     "address": {
          "@type": "PostalAddress",
          "streetAddress": "1134 Pine Tree Lane ",
          "addressLocality": "Libertyville",
          "addressRegion": "IL",
          "addressCountry": "United States",
          "postalCode": "60048"
     },
     "areaServed": {
          "@type": "GeoCircle",
          "geoMidpoint": {
               "@type": "GeoCoordinates",
               "latitude": "41.8781",
               "longitude": "87.6298"
          },
          "geoRadius": "5000 km"
     },
     "telephone": "312-620-0386",
     "email": "contact@bitovi.com",
     "sameAs": [
          "https://www.facebook.com/BitoviLLC/",
          "https://twitter.com/bitovi",
          "https://www.linkedin.com/company/bitovi"
     ]
}
```