Greetings!
In this fourth installment of our simple NgRx example series we are going to have a look at effects. Yet again, our example will be very simple.
This is the complete example https://github.com/slmanju/ngrx-at-slmanju/tree/main/ngrx-hello-effects
ngrx-hello-effects/src/app/store/app.state.ts
Effects can capture the action dispatched from a component, call the backend service, modify the response or handle errors if needed and then dispatch new action with new data. Our reducers can capture this new action.
To create an effect, there is another createXXX function provided by NgRx. For the simplicity, we are going to fake this using a timer delay.
ngrx-hello-effects/src/app/store/app.effects.ts
Just like reducers, we need to register effects in our app.module
ngrx-hello-effects/src/app/app.component.ts
Happy coding ;)
In this fourth installment of our simple NgRx example series we are going to have a look at effects. Yet again, our example will be very simple.
This is the complete example https://github.com/slmanju/ngrx-at-slmanju/tree/main/ngrx-hello-effects
What we need
- Store with initial state
- Create action to add, remove http status codes
- Create reducers act upon actions
- Create selector to read from store
- Create an effect to store http status url
- Register the reducer
- Register the effect
Generate the Project
ng new ngrx-hello-effects --routing=false --style=css
cd ngrx-hello-effects/
ng add @ngrx/store@latest
ng add @ngrx/effects@latest
ng serve
Create the Store
At this point i'll asume that you have atleast little idea about the action, reducer and selectors. Hence i'll just add the code. One change i'm doing here to previous examples is I have created separate files.ngrx-hello-effects/src/app/store/app.state.ts
export interface HttpCodeState {
code: number,
url: string
};
export interface AppState {
statusCodes: HttpCodeState[]
};
export const initialState: HttpCodeState[] = [];
ngrx-hello-effects/src/app/store/app.actions.tsimport { createAction, props } from '@ngrx/store';
import { HttpCodeState } from './app.state';
export const add = createAction('[Http Status] Add', props<{ code : number}>());
export const remove = createAction('[Http Status] Remove', props<{ code : number}>());
export const addUrl = createAction('[Http Status] Add Url', props<HttpCodeState>());
ngrx-hello-effects/src/app/store/app.reducer.tsimport { Action, createReducer, on } from '@ngrx/store';
import { addUrl, remove } from './app.actions';
import { HttpCodeState, initialState } from './app.state';
const _statusCodeReducer = createReducer(
initialState,
on(remove, (state, action) => state.filter(http => http.code !== action.code)),
on(addUrl, (state, action) => [...state, { code: action.code, url: action.url }])
);
export function statusCodeReducer(state: HttpCodeState[] = initialState, action: Action) {
return _statusCodeReducer(state, action);
}
ngrx-hello-effects/src/app/store/app.selector.tsimport { AppState } from "./app.state";
export const selectCodes = (state: AppState) => state.statusCodes;
Now let's create our effect.Create the Effect
In a real-world application we need to fetch data from our backend. What we have previousely done is storing objects in browser(sort of). We need somewhere to actually save, retrieve those values from our server back end. In NgRx world, Effects are responsible for those kind of things.Effects can capture the action dispatched from a component, call the backend service, modify the response or handle errors if needed and then dispatch new action with new data. Our reducers can capture this new action.
To create an effect, there is another createXXX function provided by NgRx. For the simplicity, we are going to fake this using a timer delay.
ngrx-hello-effects/src/app/store/app.effects.ts
import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { timer } from 'rxjs';
import { map, mergeMap } from 'rxjs/operators';
import { add, addUrl } from './app.actions';
@Injectable()
export class HttpUrlEffects {
constructor(private actions$: Actions) {}
readonly addUrl = createEffect(() =>
this.actions$.pipe(
ofType(add),
mergeMap((action) => {
return timer(10)
.pipe(
map(() => addUrl({ code: action.code, url: 'https://http.cat/' + action.code }))
);
})
));
}
Here we are responding to the actions of type add then dispatch another action named addUrl.
EffectsModule.forRoot([ HttpUrlEffects ])
There is nothing special
about the component though below is the code for the completions.ngrx-hello-effects/src/app/app.component.ts
import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs';
import { add, remove } from './store/app.actions';
import { selectCodes } from './store/app.selector';
import { AppState, HttpCodeState } from './store/app.state';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
code$: Observable<HttpCodeState[]>;
statusCode: number;
constructor(private httpStatusStore: Store<AppState>) {
this.code$ = httpStatusStore.select(selectCodes);
}
onAdd() {
this.httpStatusStore.dispatch(add({ code: this.statusCode }));
}
onRemove() {
this.httpStatusStore.dispatch(remove({ code: this.statusCode }));
}
}
That is it! It is not that hard. Get the full code from here
https://github.com/slmanju/ngrx-at-slmanju/tree/main/ngrx-hello-effects and have
fun.Happy coding ;)
Comments
Post a Comment