Angular NgRx With Effects
When working with NgRx and HTTP requests, you can use the @ngrx/effects
library to handle side effects like making HTTP requests. Here’s a step-by-step guide on how to implement NgRx with HTTP effects in an Angular application:
Setup Your Angular Project: Make sure you have an Angular project set up. You can create a new project using Angular CLI if you haven’t already:
ng new your-project-name
Install NgRx: Install the required NgRx packages:
npm install @ngrx/store @ngrx/effects @ngrx/entity @ngrx/store-devtools
Create a Store: Create a store for your application by defining your actions, reducers, and the initial state.
// app-state.ts
export interface AppState {
data: Data[];
}
// data.actions.ts
import { createAction, props } from '@ngrx/store';
export const loadData = createAction('[Data] Load Data');
export const loadDataSuccess = createAction(
'[Data] Load Data Success',
props<{ data: Data[] }>()
);
export const loadDataFailure = createAction(
'[Data] Load Data Failure',
props<{ error: any }>()
);
// data.reducer.ts
import { createReducer, on } from '@ngrx/store';
import { initialState } from './data.state';
import { loadDataSuccess, loadDataFailure } from './data.actions';
const _dataReducer = createReducer(
initialState,
on(loadDataSuccess, (state, { data }) => ({ ...state, data })),
on(loadDataFailure, (state, { error }) => ({ ...state, error }))
);
export function dataReducer(state, action) {
return _dataReducer(state, action);
}
// data.state.ts
export const initialState: AppState = {
data: [],
};
Create an Effects Class: Create an effects class to handle HTTP requests and dispatch actions accordingly. Make sure to inject the Actions
and HttpClient
services.
// data.effects.ts
import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { of } from 'rxjs';
import { catchError, map, mergeMap } from 'rxjs/operators';
import { DataService } from './data.service';
import { loadData, loadDataSuccess, loadDataFailure } from './data.actions';
@Injectable()
export class DataEffects {
constructor(
private actions$: Actions,
private dataService: DataService // Your HTTP service
) {}
loadData$ = createEffect(() =>
this.actions$.pipe(
ofType(loadData),
mergeMap(() =>
this.dataService.getData().pipe(
map((data) => loadDataSuccess({ data })),
catchError((error) => of(loadDataFailure({ error })))
)
)
)
);
}
Create a Service: Create an Angular service to handle the HTTP requests. Make sure to inject the HttpClient
service.
// data.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class DataService {
private apiUrl = 'your-api-url';
constructor(private http: HttpClient) {}
getData(): Observable<Data[]> {
return this.http.get<Data[]>(this.apiUrl);
}
}
Configure NgRx: In your app.module.ts
, configure NgRx with your store, reducers, and effects:
// app.module.ts
import { StoreModule } from '@ngrx/store';
import { EffectsModule } from '@ngrx/effects';
import { dataReducer } from './data/data.reducer';
import { DataEffects } from './data/data.effects';
@NgModule({
declarations: [/* ... */],
imports: [
BrowserModule,
StoreModule.forRoot({ app: dataReducer }),
EffectsModule.forRoot([DataEffects]),
// ...
],
// ...
})
export class AppModule {}
Dispatch Actions: In your component, you can dispatch the loadData
action to trigger the HTTP request:
// data.component.ts
import { Component, OnInit } from '@angular/core';
import { Store } from '@ngrx/store';
import { loadData } from './data/data.actions';
@Component({
selector: 'app-data',
templateUrl: './data.component.html',
})
export class DataComponent implements OnInit {
constructor(private store: Store) {}
ngOnInit() {
this.store.dispatch(loadData());
}
}
Use State in Your Component: To access the data in your component, you can select it from the store using the select
method:
// data.component.ts
import { Component, OnInit } from '@angular/core';
import { Store, select } from '@ngrx/store';
import { AppState } from './data/data.state';
@Component({
selector: 'app-data',
templateUrl: './data.component.html',
})
export class DataComponent implements OnInit {
data$ = this.store.pipe(select((state: AppState) => state.data));
constructor(private store: Store) {}
ngOnInit() {
this.store.dispatch(loadData());
}
}
Now, you have set up NgRx with HTTP effects in your Angular application. When the component initializes, it dispatches the loadData
action, which triggers the HTTP request and updates the state in the store. You can also handle error cases by catching them in the effects class and dispatching appropriate failure actions.