Wednesday, June 16, 2021

NgRx State Management

The NgRx Store is a Redux-inspired state management system that enables you to use observables to manage state in an Angular application. 
 NgRx uses the Redux pattern, which is comprised of three main concepts: 
 
Store, a central store that holds all of the application state 

Action, A unique event dispatched from components and services that describe how the state should be changed. For example, ‘Add Customer’ can be an action that will change the state (i.e. add a new customer to the list). 

Reducers, which tie the store and actions together by using the defined action to carry out a state transition, depending on the action All the state changes happen inside the reducer; it responds to the action and, based on that action, it will create a new immutable state and return it to the store. 

Selector: Selector is a function used for obtaining a part of the state from the store. 

Effect: A mechanism that listens for dispatched actions in an observable stream, processes the server response, and returns new actions either immediately or asynchronously to the reducer to change the state. Please note that we are not using 'effect' in this example app. 

 Defining State and Reducers


export interface WeatherState { weatherData: WeatherData| null; } const initialWeatherState: WeatherState = { weatherData: null }; export interface LocationState { location: LocationData| null; error: string| null; } const initialLocationState: LocationState = { location: null, error: null }; export interface AppState { weather: WeatherState; location: LocationState; }

Reducer


export function weatherReducer(state: WeatherState = initialWeatherState, action: WeatherAction): WeatherState { switch (action.type) { case WeatherActionTypes.LoadWeather: return { weatherData: action.payload.weatherData }; default: return state; } } export function locationReducer(state: LocationState = initialLocationState, action: LocationAction): LocationState { switch (action.type) { case LocationActionTypes.LoadLocations: return { location: action.payload.locationData, error: null }; case LocationActionTypes.LocationsError: return { location: null, error: action.payload.error }; default: return state; } } export const reducers: ActionReducerMap<AppState> = { weather: weatherReducer, location: locationReducer };

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:

<>Copy
import { 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:

Followers

Link