Defining State and Reducers
Reducer
Defining Actions
The next step is to define the actions that will dispatch changes to the storeusing the application state and reducers
Actions should be treated as events, and live close to where they are dispatched from. It’s also a good idea to include the name of the page that the action is being fired from when you declare the action type. So for example “[Home Page] load locations” would be an action of type LoadLocation fired from the Home Page.
Open up the actions/location.actions.ts
file, and copy & paste the following into it:
<>Copyimport { Action } from '@ngrx/store'; import { LocationData } from '../models/location-data/location-data'; export enum LocationActionTypes { LoadLocations = '[Home Page] Load Locations', LocationsError = '[Home Page] Locations Error' } export class LocationAction implements Action { type: string; payload: { locationData: LocationData, error: string }; } export class LoadLocations implements Action { readonly type = LocationActionTypes.LoadLocations; constructor(readonly payload: {locationData: LocationData}) { } } export class LocationsError implements Action { readonly type = LocationActionTypes.LocationsError; constructor(readonly payload: {error: string}) { } }
//Finally, you see these action classes being exported out to the project:
export type ActionsUnion = LoadLocations | LocationsError;
Creating an Effect for the Actions
With the actions and reducers setup, the last step is to build out an effect that will run whenever the location is updated. Basically we want to set it up so anytime the location changes, a new weather forecast is retrieved.
Effects occur as a result from actions, and can also create actions when called. Effects primary responsibility is to create async side-effects (like service calls to APIs), that ultimately generate other actions.
We write down the api call inside effects.
import { Injectable } from '@angular/core'; import { Actions, Effect, ofType } from '@ngrx/effects'; import { LoadWeather } from './weather.actions'; import { map, mergeMap, catchError } from 'rxjs/operators'; import { AppState } from '../reducers'; import { Store } from '@ngrx/store'; import { WeatherService } from './weather.service'; import { LocationActionTypes, LocationsError, LoadLocations } from './location.actions'; import { of } from 'rxjs'; @Injectable() export class WeatherEffects { @Effect() loadLocation$ = this.actions$ .pipe( ofType<LoadLocations>(LocationActionTypes.LoadLocations), mergeMap((action) => this.weatherService.getWeather(action.payload.locationData) .pipe( map(weather => { return (new LoadWeather({weatherData: weather})); }), catchError((errorMessage) => of(new LocationsError({error: errorMessage}))) )) ); constructor(private actions$: Actions, private store: Store<AppState>, private weatherService: WeatherService) { } }
So what’s this doing and how does this work?
- Using the
Effect
decorator, the application’s instance of NgRx becomes aware of this effect on startup. - This effect listens for actions of type LoadLocations and then uses mergeMap to pass the location data from the action to a call to the applications weather service.
- Then the effect will dispatch a new LoadWeather action to include the new forecast information.
- When the dispatch to the store is complete, the store is updated
- If there are any errors that occur in the service call, the effect dispatches a LocationsError action with the error to the store.
For a more detailed walkthrough of how the error handling works, please checkout my post Exception Handling with NgRx Effects. Special thanks to Tim Deschryver and Alex Okrushko for their help with this.
Source : https://indepth.dev/posts/1042/how-to-start-flying-with-angular-and-ngrx
No comments:
Post a Comment