Un corazoncito por un curso avanzando para manejar el estado con Angular!! ❤❤❤
Grande Nico.!
Gestionar la sesión de un usuario de forma eficiente es uno de los retos más comunes al construir aplicaciones con Angular. Aunque guardar el token en local storage es un primer paso, no basta para que toda la aplicación conozca el estado del usuario en tiempo real. Aquí se explica cómo crear un estado global reactivo que permite a cualquier componente, guardián o servicio saber si existe un usuario autenticado, sin repetir peticiones innecesarias al servidor.
¿Cómo crear un store global reactivo para el usuario?
El punto de partida es el store service, donde previamente se implementó reactividad para el carrito de compras usando un BehaviorSubject. La misma técnica se aplica para el usuario [01:40].
Se define un BehaviorSubject cuyo tipo es User | null, con un valor inicial de null, lo que representa que no hay ningún usuario autenticado. A partir de ese BehaviorSubject, se expone un observable público con el sufijo $ (convención para identificar observables), permitiendo que otros componentes se suscriban al estado del usuario sin poder modificarlo directamente [02:15].
Para nutrir ese estado, se utiliza el método getProfile dentro del auth service. Cada vez que se obtiene el perfil del servidor, se ejecuta un operador tap dentro del pipe. A diferencia de switchMap, que cambia de observable, tap simplemente ejecuta una acción lateral sin mutar la información ni cambiar el flujo. En este caso, esa acción es llamar a this.user.next(usuario) para dejar al usuario en el estado global [03:12].
¿Por qué usar tap en lugar de switchMap?
El operador switchMap se emplea cuando necesitas cambiar de un observable a otro. Si solo quieres realizar una acción secundaria —como guardar datos en un store— sin alterar el flujo del observable, tap es la opción correcta [04:00]. Esto mantiene el código limpio y semánticamente preciso.
¿Cómo se aprovecha el estado global en los guardianes?
En el auth guard, en lugar de verificar directamente si existe un token mediante el token service, ahora se consulta el observable del usuario [04:30]. El guardián retorna un observable que emite un booleano gracias al operador map:
null, se ejecuta la redirección al home y se retorna false.true.Esto es posible porque Angular permite que un guardián retorne un boolean, una Promise<boolean> o un Observable<boolean> [05:05].
¿Cómo evitar peticiones duplicadas de perfil?
Uno de los beneficios más importantes de este patrón es eliminar llamadas redundantes al endpoint de perfil. Antes, el componente de profile hacía su propio getProfile. Ahora, como el perfil ya se obtuvo durante el login (mediante el método loginAndGet), el componente simplemente se suscribe al estado global y obtiene la información sin hacer ninguna petición HTTP adicional [06:10].
En el componente de navegación también se aplica el mismo principio. En el ngOnInit, se suscribe al observable del usuario para actualizar la interfaz de forma reactiva cada vez que el estado cambie [07:00].
¿Qué pasa cuando el usuario recarga la página?
El BehaviorSubject inicia en null cada vez que la aplicación se carga, lo que significa que al recargar se pierde el estado. La solución se implementa en el app component, que es el punto de entrada de toda la aplicación [08:10].
En su ngOnInit, se inyectan el auth service y el token service. La lógica es sencilla:
getProfile una única vez.getProfile tiene el tap que nutre el BehaviorSubject, todos los componentes suscritos reciben automáticamente al usuario [09:00].De esta forma, el flujo completo funciona así:
null y los guardianes bloquean el acceso a rutas protegidas.¿Cómo se verifica que todo funciona correctamente?
Al hacer login, el usuario es redirigido al profile y tanto la barra de navegación como el componente de perfil muestran la información sin peticiones extra [10:15]. Al hacer logout, el estado se limpia y los guardianes impiden el acceso a rutas protegidas, devolviendo al usuario al home [10:45]. Al recargar la página estando autenticado, el app component recupera la sesión y la aplicación continúa funcionando con normalidad [11:10].
Este patrón de estado reactivo con BehaviorSubject es fundamental para escalar aplicaciones Angular. En el siguiente paso, se extiende esta lógica para proteger rutas no solo por autenticación, sino también por rol de usuario, diferenciando entre administradores y clientes. ¿Ya has implementado este patrón en tus proyectos? Comparte tu experiencia.
Gestionar la sesión de un usuario de forma eficiente es uno de los retos más comunes al construir aplicaciones con Angular. Aunque guardar el token en local storage es un primer paso, no basta para que toda la aplicación conozca el estado del usuario en tiempo real. Aquí se explica cómo crear un estado global reactivo que permite a cualquier componente, guardián o servicio saber si existe un usuario autenticado, sin repetir peticiones innecesarias al servidor.
El punto de partida es el store service, donde previamente se implementó reactividad para el carrito de compras usando un BehaviorSubject. La misma técnica se aplica para el usuario [01:40].
Se define un BehaviorSubject cuyo tipo es User | null, con un valor inicial de null, lo que representa que no hay ningún usuario autenticado. A partir de ese BehaviorSubject, se expone un observable público con el sufijo $ (convención para identificar observables), permitiendo que otros componentes se suscriban al estado del usuario sin poder modificarlo directamente [02:15].
Para nutrir ese estado, se utiliza el método getProfile dentro del auth service. Cada vez que se obtiene el perfil del servidor, se ejecuta un operador tap dentro del pipe. A diferencia de switchMap, que cambia de observable, tap simplemente ejecuta una acción lateral sin mutar la información ni cambiar el flujo. En este caso, esa acción es llamar a this.user.next(usuario) para dejar al usuario en el estado global [03:12].
El operador switchMap se emplea cuando necesitas cambiar de un observable a otro. Si solo quieres realizar una acción secundaria —como guardar datos en un store— sin alterar el flujo del observable, tap es la opción correcta [04:00]. Esto mantiene el código limpio y semánticamente preciso.
En el auth guard, en lugar de verificar directamente si existe un token mediante el token service, ahora se consulta el observable del usuario [04:30]. El guardián retorna un observable que emite un booleano gracias al operador map:
null, se ejecuta la redirección al home y se retorna false.true.Esto es posible porque Angular permite que un guardián retorne un boolean, una Promise<boolean> o un Observable<boolean> [05:05].
Uno de los beneficios más importantes de este patrón es eliminar llamadas redundantes al endpoint de perfil. Antes, el componente de profile hacía su propio getProfile. Ahora, como el perfil ya se obtuvo durante el login (mediante el método loginAndGet), el componente simplemente se suscribe al estado global y obtiene la información sin hacer ninguna petición HTTP adicional [06:10].
En el componente de navegación también se aplica el mismo principio. En el ngOnInit, se suscribe al observable del usuario para actualizar la interfaz de forma reactiva cada vez que el estado cambie [07:00].
El BehaviorSubject inicia en null cada vez que la aplicación se carga, lo que significa que al recargar se pierde el estado. La solución se implementa en el app component, que es el punto de entrada de toda la aplicación [08:10].
En su ngOnInit, se inyectan el auth service y el token service. La lógica es sencilla:
getProfile una única vez.getProfile tiene el tap que nutre el BehaviorSubject, todos los componentes suscritos reciben automáticamente al usuario [09:00].De esta forma, el flujo completo funciona así:
null y los guardianes bloquean el acceso a rutas protegidas.Al hacer login, el usuario es redirigido al profile y tanto la barra de navegación como el componente de perfil muestran la información sin peticiones extra [10:15]. Al hacer logout, el estado se limpia y los guardianes impiden el acceso a rutas protegidas, devolviendo al usuario al home [10:45]. Al recargar la página estando autenticado, el app component recupera la sesión y la aplicación continúa funcionando con normalidad [11:10].
Este patrón de estado reactivo con BehaviorSubject es fundamental para escalar aplicaciones Angular. En el siguiente paso, se extiende esta lógica para proteger rutas no solo por autenticación, sino también por rol de usuario, diferenciando entre administradores y clientes. ¿Ya has implementado este patrón en tus proyectos? Comparte tu experiencia.
Un corazoncito por un curso avanzando para manejar el estado con Angular!! ❤❤❤
Grande Nico.!
Yo había solucionado esto guardando los datos de perfil en una variable de localStorage, pero lo que nos enseña Nico me parece mucho mejor
profile(){
return this.http.get<User>(`${this.apiUrl}/profile`)
.pipe(
tap(user =>{
localStorage.setItem('profile', JSON.stringify(user));
})
);
}
10/10 esta clase 🖖
no se puede entrar a la vista profile por medio del url, al final del video se ve como redirije al home, solo se accede dandole click al usuario, como se podría solucionar esto?
creo que sería mejor que el guard verificará si existe un token y si es posible que es un token valido
¿En que clase explican el swichMap?
Yo uso el BehaviorSubject sin luego declarar la variable como asObsevable y me funciona obteniendo los valores así this.authService.user$.value, qué diferencias hay?
Con estos cambios implementados ya no se puede ingresar directamente desde la url a profile aun teniendo una sesión iniciada? o es error mío?
¿Qué tan viable es dejar varios subscribe que no sean de HttpClient escuchando? ¿consume más recursos? ¿o debería cancelarlos al destruir los componentes? Gracias :D
Gran curso de Angular!!!