A more complex example – a list

We have so far learned how to set up NgRx by importing and registering its module. We have also been taught about the select() function that gives us a slice of state, and the dispatch() function that allows us to dispatch an action. These are the basics, we will use these very same basics and create a new reducer to reinforce what we already know, while introducing the concept payload.

We need to do the following:

  • Tell the store we have a new state, jedis
  • Create a jediListReducer and register it with the store
  • Create a component that supports showing our jediList, but is also able to dispatch actions that will change our slice of state  jedis

Let's get down to business by defining our reducer, jediListReducer:

// jedi-list.reducer.ts
export function jediListReducer(state = [], action) {
switch(action.type) {
case 'ADD_JEDI':
return [ ...state, { ...action.payload }];
case 'REMOVE_JEDI':
return state.filter(jedi => jedi.id !== action.payload.id);
case 'LOAD_JEDIS':
return action.payload.map(jedi => ({...jedi}));
default:
return state;
}
}

Let's explain what goes on here for each case in our switch. First off, we have ADD_JEDI. We take our action.payload and add it to the list. Or technically, we take our existing list and construct a new list based on the old list, plus our new list item found in action.payload.  Secondly we have REMOVE_JEDI that uses the filter() function to take away the list item that we don't want to see. Lastly we have LOAD_JEDIS that takes in an existing list and replaces our state. Now, let's demo this reducer by invoking it here:

let state = jediListReducer([], { type: 'ADD_JEDI', payload : { id: 1, name: 'Yoda' });
// now contains [{ id: 1, name: 'Yoda' }]

state = jediListReducer(state, { type: 'ADD_JEDI', payload: { id: 2, name: 'Darth Vader'} });
// now contains [{ id: 1, name: 'Yoda' }, { id: 2, name: 'Darth Vader'}];

state = jediListReducer(state, { type: 'REMOVE JEDI', payload: { id: 1 } });
// now contains [{ id: 2, name: 'Darth Vader'}];

state = jediListReducer(state, { type: 'LOAD_JEDIS', payload: [] });
// now contains []

Now, let's register this reducer with the store. We will therefore return to app.module.ts:

// app.module.ts

import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { StoreModule } from "@ngrx/store";
import { AppComponent } from "./app.component";
import { counterReducer } from "./reducer";
import { jediListReducer } from "./jedi-list-reducer";

@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
StoreModule.forRoot({
count: counterReducer,
jediList: jediListReducer }),
],
bootstrap: [AppComponent]
})
export class AppModule {}

Because we just added a new state to our store, we should make the app-state.ts file aware of it, and we should also create a Jedi model so we can use that in our component later on:

// jedi.model.ts

export interface Jedi {
id: number;
name: string;
}

// app-state.ts

import { Jedi } from "./jedi.model";

export interface AppState {
counter: number;
jediList: Array<Jedi>;
}

From the preceding code, we can see that jediListReducer, as well as the state jediList, is added to the object that serves as input to the StoreModule.forRoot() function. This means that NgRx is aware of this state and will let us retrieve it and dispatch actions to it. To do so, let's build a component with just that. We need to create the jedi-list.component.ts file:

// jedi-list.component.ts

import { Component } from "@angular/core";
import { Store } from "@ngrx/store";
import { AppState } from "../app-state";
import { Jedi } from "./jedi.model";

@Component({
selector: "jedi-list",
template: `
<div *ngFor="let jedi of list$ | async">
{{ jedi.name }}<button (click)="remove(jedi.id)" >Remove</button>
</div>
<input [(ngModel)]="newJedi" placeholder="" />
<button (click)="add()">Add</button>
<button (click)="clear()" >Clear</button>
`
})
export class JediListComponent {
list$: Observable<Array<Jedi>>;
counter = 0;
newJedi = "";

constructor(private store: Store<AppState>) {
this.list$ = store.select("jediList");
}

add() {
this.store.dispatch({
type: 'ADD_JEDI',
payload: { id: this.counter++, name: this.newJedi }
});
this.newJedi = '';
}

remove(id) {
this.store.dispatch({ type: 'REMOVE_JEDI', payload: { id } });
}

clear() {
this.store.dispatch({ type: 'LOAD_JEDIS', payload: [] });
this.counter = 0;
}
}

The last thing we need to do is to register this component with our module, and we should have a working application:

// app.module.ts

import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { StoreModule } from "@ngrx/store";
import { AppComponent } from "./app.component";
import { counterReducer } from "./reducer";
import { jediListReducer } from "./jedi-list.reducer";
import { JediListComponent } from './jedi-list.component';

@NgModule({
declarations: [AppComponent, JediListComponent ],
imports: [
BrowserModule,
StoreModule.forRoot({ count: counterReducer, jediList: JediListReducer }),
],
bootstrap: [AppComponent]
})
export class AppModule {}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.75.221