Introducción
NgRx Effects es una biblioteca que se utiliza junto con NgRx Store para manejar efectos secundarios en aplicaciones Angular. Los efectos secundarios son operaciones que interactúan con el mundo exterior, como solicitudes HTTP, acceso a almacenamiento local, o cualquier otra operación asíncrona. NgRx Effects permite gestionar estas operaciones de manera reactiva y mantener la lógica de efectos secundarios fuera de los componentes y servicios.
Objetivos
- Entender qué son los efectos en NgRx.
- Aprender a crear y manejar efectos en una aplicación Angular.
- Integrar NgRx Effects con NgRx Store para manejar operaciones asíncronas.
Conceptos Clave
- Efectos (Effects): Son clases que escuchan acciones despachadas al Store y realizan operaciones asíncronas en respuesta a esas acciones.
- Acciones (Actions): Son objetos que describen eventos que ocurren en la aplicación.
- Observables: NgRx Effects utiliza observables para manejar operaciones asíncronas.
Instalación
Antes de comenzar, asegúrate de tener NgRx Effects instalado en tu proyecto Angular. Puedes instalarlo usando npm:
Creación de Efectos
Paso 1: Definir Acciones
Primero, definimos las acciones que desencadenarán los efectos. Por ejemplo, si estamos manejando una lista de productos, podríamos tener acciones para cargar productos, cargar productos exitosamente y manejar errores.
// actions/product.actions.ts import { createAction, props } from '@ngrx/store'; export const loadProducts = createAction('[Product] Load Products'); export const loadProductsSuccess = createAction( '[Product] Load Products Success', props<{ products: Product[] }>() ); export const loadProductsFailure = createAction( '[Product] Load Products Failure', props<{ error: any }>() );
Paso 2: Crear el Efecto
A continuación, creamos una clase de efectos que escuche las acciones y realice las operaciones asíncronas necesarias.
// effects/product.effects.ts import { Injectable } from '@angular/core'; import { Actions, createEffect, ofType } from '@ngrx/effects'; import { ProductService } from '../services/product.service'; import { loadProducts, loadProductsSuccess, loadProductsFailure } from '../actions/product.actions'; import { catchError, map, mergeMap } from 'rxjs/operators'; import { of } from 'rxjs'; @Injectable() export class ProductEffects { constructor( private actions$: Actions, private productService: ProductService ) {} loadProducts$ = createEffect(() => this.actions$.pipe( ofType(loadProducts), mergeMap(() => this.productService.getProducts().pipe( map(products => loadProductsSuccess({ products })), catchError(error => of(loadProductsFailure({ error }))) ) ) ) ); }
Paso 3: Registrar los Efectos
Finalmente, registramos los efectos en el módulo de efectos de NgRx.
// app.module.ts import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { StoreModule } from '@ngrx/store'; import { EffectsModule } from '@ngrx/effects'; import { ProductEffects } from './effects/product.effects'; import { productReducer } from './reducers/product.reducer'; @NgModule({ declarations: [AppComponent], imports: [ BrowserModule, StoreModule.forRoot({ products: productReducer }), EffectsModule.forRoot([ProductEffects]) ], providers: [], bootstrap: [AppComponent] }) export class AppModule {}
Ejercicio Práctico
Ejercicio
- Objetivo: Crear un efecto que cargue una lista de usuarios desde una API y maneje los estados de éxito y error.
- Pasos:
- Define las acciones
loadUsers
,loadUsersSuccess
yloadUsersFailure
. - Crea un servicio
UserService
que tenga un métodogetUsers
para obtener la lista de usuarios. - Implementa una clase de efectos
UserEffects
que maneje la acciónloadUsers
y despacheloadUsersSuccess
oloadUsersFailure
según corresponda. - Registra los efectos en el módulo de efectos de NgRx.
- Define las acciones
Solución
Definir Acciones
// actions/user.actions.ts import { createAction, props } from '@ngrx/store'; export const loadUsers = createAction('[User] Load Users'); export const loadUsersSuccess = createAction( '[User] Load Users Success', props<{ users: User[] }>() ); export const loadUsersFailure = createAction( '[User] Load Users Failure', props<{ error: any }>() );
Crear Servicio
// services/user.service.ts import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { User } from '../models/user.model'; @Injectable({ providedIn: 'root' }) export class UserService { private apiUrl = 'https://api.example.com/users'; constructor(private http: HttpClient) {} getUsers(): Observable<User[]> { return this.http.get<User[]>(this.apiUrl); } }
Implementar Efectos
// effects/user.effects.ts import { Injectable } from '@angular/core'; import { Actions, createEffect, ofType } from '@ngrx/effects'; import { UserService } from '../services/user.service'; import { loadUsers, loadUsersSuccess, loadUsersFailure } from '../actions/user.actions'; import { catchError, map, mergeMap } from 'rxjs/operators'; import { of } from 'rxjs'; @Injectable() export class UserEffects { constructor( private actions$: Actions, private userService: UserService ) {} loadUsers$ = createEffect(() => this.actions$.pipe( ofType(loadUsers), mergeMap(() => this.userService.getUsers().pipe( map(users => loadUsersSuccess({ users })), catchError(error => of(loadUsersFailure({ error }))) ) ) ) ); }
Registrar Efectos
// app.module.ts import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { StoreModule } from '@ngrx/store'; import { EffectsModule } from '@ngrx/effects'; import { UserEffects } from './effects/user.effects'; import { userReducer } from './reducers/user.reducer'; @NgModule({ declarations: [AppComponent], imports: [ BrowserModule, StoreModule.forRoot({ users: userReducer }), EffectsModule.forRoot([UserEffects]) ], providers: [], bootstrap: [AppComponent] }) export class AppModule {}
Conclusión
NgRx Effects es una herramienta poderosa para manejar operaciones asíncronas en aplicaciones Angular de manera reactiva. Al separar la lógica de efectos secundarios de los componentes y servicios, se mejora la mantenibilidad y la claridad del código. En este módulo, aprendiste a definir acciones, crear efectos y registrarlos en tu aplicación Angular. Con esta base, puedes manejar cualquier operación asíncrona en tu aplicación de manera eficiente y organizada.
Curso de Angular
Módulo 1: Introducción a Angular
- ¿Qué es Angular?
- Configuración del Entorno de Desarrollo
- Arquitectura de Angular
- Primera Aplicación Angular
Módulo 2: Componentes de Angular
- Entendiendo los Componentes
- Creación de Componentes
- Plantillas de Componentes
- Estilos de Componentes
- Interacción entre Componentes
Módulo 3: Enlace de Datos y Directivas
- Interpolación y Enlace de Propiedades
- Enlace de Eventos
- Enlace de Datos Bidireccional
- Directivas Incorporadas
- Directivas Personalizadas
Módulo 4: Servicios e Inyección de Dependencias
- Introducción a los Servicios
- Creación y Uso de Servicios
- Inyección de Dependencias
- Inyectores Jerárquicos
Módulo 5: Enrutamiento y Navegación
Módulo 6: Formularios en Angular
- Formularios Basados en Plantillas
- Formularios Reactivos
- Validación de Formularios
- Formularios Dinámicos
Módulo 7: Cliente HTTP y Observables
- Introducción al Cliente HTTP
- Realizando Solicitudes HTTP
- Manejo de Respuestas HTTP
- Uso de Observables
- Manejo de Errores
Módulo 8: Gestión de Estado
- Introducción a la Gestión de Estado
- Uso de Servicios para la Gestión de Estado
- NgRx Store
- NgRx Effects
- NgRx Entity
Módulo 9: Pruebas en Angular
- Pruebas Unitarias
- Pruebas de Componentes
- Pruebas de Servicios
- Pruebas de Extremo a Extremo
- Simulación de Dependencias
Módulo 10: Conceptos Avanzados de Angular
- Angular Universal
- Optimización del Rendimiento
- Internacionalización (i18n)
- Pipes Personalizados
- Animaciones en Angular