Alex Leonardo Rodriguez Carvajal
Like si tambien te gustaria un curso dedicado a RXJS.
José Pablo Jiménez Cucanán
voto por uno de ngRx también
Sebastian Sanmartin
Rxjs y ngRx apoyo
El concepto de reactividad básica es muy importante en el desarrollo front-end. Se trata del estado de la aplicación con respecto al valor de los datos en cada componente, cómo estos cambian a medida que el usuario interactúa y cómo se actualiza la interfaz.
Problemas en la comunicación de componentes
Cuando pensamos en cómo comunicar un componente padre con su hijo y viceversa, solemos utilizar los decoradores @Input() y @Output().
Pero muchas veces, en aplicaciones grandes, la comunicación de componentes se vuelve mucho más compleja y estas herramientas no alcanzan cuando se necesita enviar información de un componente ""hijo"" a uno ""abuelo"".
Solución a la comunicación de componentes
Es recomendable implementar un patrón de diseño para mantener el estado de la aplicación centralizado en un único punto, para que todos los componentes accedan a ellos siempre que necesiten. A este punto central se lo conoce como Store.
Implementando un store de datos
Los store de datos suelen implementarse haciendo uso de Observables.
Paso 1:
Importa la clase BehaviorSubject desde la librería RxJS, que te ayudará a crear una propiedad observable, a la cual tu componente pueda suscribirse y reaccionar ante ese cambio de estado.
// services/store.service.ts import { BehaviorSubject } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class StoreService { private myShoppingCart: Producto[] = []; private myCart = new BehaviorSubject<Producto[]>([]); public myCart$ = this.myCart.asObservable(); constructor() { } addProducto(producto: Producto): void { // El observable emitirá un nuevo valor con cada producto que se agregue al carrito. this.myShoppingCart.push(producto); this.myCart.next(this.myShoppingCart); } }
Paso 2: Suscribe a cualquier componente que necesites a estos datos, para reaccionar cuando estos cambian.
// components/nav-bar/nav-bar.component.ts import { StoreService } from 'src/app/services/store.service'; import { Subscription } from 'rxjs'; @Component({ selector: 'app-nav-bar', templateUrl: './nav-bar.component.html', styleUrls: ['./nav-bar.component.scss'] }) export class NavBarComponent implements OnInit, OnDestroy { private sub$!: Subscription; constructor( private storeService: StoreService ) { } ngOnInit(): void { this.storeService.myCart$ .subscribe(data => { // Cada vez que el observable emita un valor, se ejecutará este código console.log(data); }); } ngOnDestroy(): void { this.sub$.unsubscribe(); } }
El lugar más apropiado para esto es en ngOnInit(). No olvides guardar este observable en una propiedad del tipo Subscription para hacer un unsubscribe() cuando el componente sea destruido.
NOTA: Por convención, las propiedades que guardan observables suelen tener un ""$"" al final del nombre para indicar que se trata de un observable.
Ver código fuente del proyecto
Contribución creada con los aportes de Kevin Fiorentino.
Alex Leonardo Rodriguez Carvajal
Like si tambien te gustaria un curso dedicado a RXJS.
José Pablo Jiménez Cucanán
voto por uno de ngRx también
Sebastian Sanmartin
Rxjs y ngRx apoyo
Malena Lucero
Coincido con los comentarios, hace falta un curso especifico de Rxjs en Angular
Mariano Tribuj
Es un tema súper importante y merece un curso propio. Tengo la duda de cómo evitar que el contador reinicie cuando el usuario refresca la pantalla? Que opciones hay? Es una buena practica usar LocalStorage?
Victor Manuel Franco Cañon
Puedes utilizar los eventos del ciclo de vida de un componente para lo que indicas, segun sea el caso podrias utilizar un evento cuando el usuario carga componente (ngOnInit) u en donde lo prefieras incluso en un evento con una validacion personalizada.
!Eventos en Angular
Conceptos extraídos de:
Mariano Tribuj
Victor gracias por la respuesta. Los eventos de ciclo de vida los tengo claro, el problema sucede cuando el usuario actualiza la pantalla el contador se va a volver a cero por mas que guardes el valor en un servicio, simplemente porque al actualizar la app se reinicia, por lo tanto la instancia del servicio es otra. Para evitar eso y que tome el valor que el contador tenia previo a actualizar la pantalla, es necesario de LocalStorage, lo que no se si es buena practica.
Mateo Costa
También todo mi apoyo para un curso de reactividad con RxJS y NGRx en Angular.
Sebastian Arrieta Villarreal
O NGXs
Daniel Meza
José Rafael Ramírez Zavaleta
Excelente aporte
Diego Fernando Caviedes Camaho
como declararías el array de tipo subscriptions?
Victor Manuel Franco Cañon
Seria super bueno que indicaran como se utlizan los test de cada proceso
Cecilia Riveros
Quiero un curso de RXJS para Angular
Jimmy Buriticá Londoño
Programación Reactiva
La programación reactiva sigue el patrón de diseño Observer; cuando hay un cambio de estado en un objeto, los otros objetos son notificados y actualizados acorde.
Diego Fernando Caviedes Camaho
también trabaja con el patrón de diseño iterator https://www.educative.io/edpresso/how-observer-and-iterator-patterns-work-in-rxjs
William Armando Forero Bermeo
Entender esta parte de reactividad ha hecho que haga un refactoring impresionante a mis proyectos, que excelente curso el del profe !
Obed Paz
Ya entendi porque sentia que me costaba un poco mas entender React que otros frameworks o librerias.
Sergio Andrés Bolaños Penagos
Estilos que les pueden servir para su contador
.shopping-cart-container { position: relative; display: block; .counter { position: absolute; right: -12px; top: -4px; color: #fefefe; font-size: 12px; width: 20px; height: 20px; border-radius: 50%; text-align: center; line-height: 20px; background-color: #458f4b; } }
Gabriel Diaz
eres un grande, gracias
moises mannarino
apoyo la idea de que se hagan una serie de cursos sobre rxjs y reactividad en angular
David Castro
Me sumo, yo también apoyo esa propuesta. Vamos platzi!
Kevin Zavala
Muy buena explicación. El manejo de estado mediante un servicio nos quita de varias cosas como la comunicación que tendríamos que desarrollar para hacerlo por medio de inputs y outputs. Me gustaría saber su opinión de NGRX, aún se sigue usando o realmente hay mejores herramientas para mejorar el estado?
Diego Fernando Caviedes Camaho
Tengo una gran pregunta, en foros he visto que al utilizar asObservable elimina la implementación del Observador(Observer). Por lo tanto, no puede llamar a next, error & complete en la instancia devuelta por asObservable(). que en typescriipt seria mejor hacer esto:
private messageSubject = new BehaviorSubject<any>(undefined); public messages$: Observable<any> = this.messageSubject;
Andres López
Diego Fernando Caviedes Camaho
te falta el atributo myCart$ = this.cart.asObservable();
Vsqz Gabriel
Luis Abdel Rangel Castro
Nice!
Sergio Ramirez
hola, me puede explicar algo, no entiendo la sintaxis del parametro que estas enviando en el metodo next donde envias [... this.myCartState.value, product]. Gracias
emely dayanna tarazona perez
Quiero utilizar la reactividad en mi código . En mis servicios tengo un post a una API, ¿Cómo implemento el BehabiorSubject en este caso?
Nicolas Molina
ProfesorHola, si bien puedes seguir usando el BehaviorSubject sin problema con rxjs también más adelante en este curso vemos como trabajar con las signals directamente en los servicios, ahora si quieres unir rxjs + signls Angular tiene un paquete para convertir de signal a observable y viceversa.
Más info en https://angular.dev/guide/signals/rxjs-interop
Luis Abdel Rangel Castro
Que bonito es lo bonito :)
Donny Daniel Vásquez Ramos
Es la 5ta vez que me veo este video. Jajajaja, el impostor me está atacando!
Algo super importante cuando existen subscripciones a observables que no son de http o de route (que por sí mismas se destruyen), es que debemos manejar su destrucción del componente. Esto porque puede generar un memory leak.
Yo creé un método que realizara la suscripción y la retornara para manejarla.
getMyCartLength(): Subscription { return this._storeService.myCart$ .subscribe(products => { this.counter = products.length; }); }
Y dentro del onInit() la almaceno en una variable o arreglo (en caso que deba manejar más de una subscripción a observables) de tipo Subscription. Ej:
ngOnInit(): void { // Si se tendrán más subscripciones this.subscriptions = [ this.getMyCartLength() ] // Manejar una sola subscripción this.subscription = this.getMyCartLength() }
Todo esto, para que cuando el componente de desmonte, y se ejecute el método onDestroy() del ciclo de vida. También destruya las subscripciones que tiene activas.
ngOnDestroy(): void { // Si se tendrán más subscripciones this.subscriptions.forEach(sub => { if (sub !== null) { sub.unsubscribe() } }); // Manejar una sola subscripción this.subscription ? this.subscription.unsubscribe() : null; }
Tengo problemas al usar .next() porque me aparece que ese método no existe en el observable así que trate de hacerlo como dices pero sigue sin funcionar.
En mi código tengo algo como esto
private cart = new BehaviorSubject<Product[]>([]); // Agregar producto al carrito addtoCart(product: Product) { this.shoppingCart.push(product); // Transmitir el estado this.cart$.next(...) }