A Home-made Redux Store

I created a code template/guide on how to create a simple Redux-store for Angular. You can find it in my Gist: Home Made Redux Store

Captain out…


Home-made Redux Store

This is a simple/small Redux Store implementation for small angular apps.
Use in case you don’t want to use the full-blown Redux libraries out there, for the sake of simplicity.

This template code is based and inspired on Ultimate Angular - NGRX Store + Effects Online Training (Free).
Highly recommended.

The example below is based on a super simple fictional ‘Agenda’ app where we can add contacts and to-do tasks.

Step 1: Copy the Home-Made Redux Store code

Copy into your application the following files, from this Gist that form the ‘Home-Made Redux Store’ class.

Step 2: Define your state

Now define your AppState interface and its substates

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
export interface IContact {

name: string;
email: string;

}

export interface ITask {

description: string;
done: boolean;

}


export interface IAppState {

contacts: IContact[];
tasks: ITask[];

}

Step 3: Define the initial state

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
export const initialState: IAppState = {
contacts: [
{
name: "Me",
email: "me@example.com"
}
],

tasks: [
{
description: "Start populating this list",
done: false
}
]
}

Step 4: Define your action types

1
2
3
4
export enum ActionTypes {
ADD_CONTACT,
ADD_TASK
}

Step 5: Define your actions and their payloads

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
export class TaskAction implements IAction {
public readonly type = ActionTypes.ADD_TASK

constructor (
public payload: ITask
){}
}

export class ContactAction implements IAction {

constructor(
public payload: IContact
) {

}

public readonly type = ActionTypes.ADD_CONTACT;

}

Step 6: Define your reducers (functions)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const contactsReducer: IReducer = function (state: IContact[], action: ContactAction) {
switch (action.type) {
case ActionTypes.ADD_CONTACT: {
const contacts = [...state, action.payload];
return contacts;
}
}
return state;
};

const tasksReducer: IReducer = function (state: ITask[], action: TaskAction) {
switch (action.type) {
case ActionTypes.ADD_TASK: {
const tasks = [...state, action.payload];
return tasks;
}
}
return state;
}

export const reducers: IReducers = {
contacts: contactsReducer,
tasks: tasksReducer
};

Step 7: Instanciate the store as your own service

In this example, the State Service extends the HomeMadeReduxStore class. Alternatively you could build a wrapper service
that utilizes the HomeMadeReduxStore class.

1
2
3
4
5
6
7
8
9
10
11
@Injectable()
export class AppStateService extends HomeMadeReduxStore<IAppState> {

constructor(
reducers: IReducers = {},
initialState: IAppState = <IAppState>{}
) {
super(reducers, initialState);
}

}

Step 8: Inject your service into your module

In this example we instanciate the service with our specific state and reducers.

app.module.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule
],
providers: [
{provide: AppStateService, useFactory(){
return new AppStateService(reducers,initialState);
}}
],
bootstrap: [AppComponent]
})
export class AppModule { }

Step 9: Start using the store by dispatching actions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import { TaskAction } from './app-state/actions/task-action';
import { AppStateService } from './app-state/app-state.service';
import { Component } from '@angular/core';
import { ContactAction } from './app-state/actions/contact-action';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';

constructor(
private appState: AppStateService
){

console.log('Intial State:', this.appState.value);

this.appState.dispatch(new ContactAction ({
name: "John Doe",
email: "johndoe@example.com"
}));
console.log('Adding contact', this.appState.value);

this.appState.dispatch(new TaskAction ({
description: 'Buy groceries',
done: false
}));
console.log('Added task', this.appState.value);

}

}