Cuándo y por qué usar REDUX NgRx en Angular

En un artículo anterior escribí sobre cómo manejar el estado en Angular usando servicios, pero cuando la aplicación crece y necesita rastrear y gestionar un estado grande, la situación se vuelve compleja y difícil de mantener. Por ejemplo, cuando tenemos muchos componentes que necesitan reaccionar a esos cambios de estado.
Al principio, usar un servicio con un BehaviorSubject es sencillo, pero a veces empezamos a encontrar problemas o efectos secundarios que hacen difícil identificar exactamente dónde ocurre el error.
En nuestras aplicaciones solemos manejar varios tipos de estado: a veces persistente en el backend y proveniente de una API, en la URL como http://myapp.com/users?id=2, o dentro de un solo componente. Entonces, ¿cuándo necesito realmente usar NgRx? 🤔
¿Realmente necesitas usar NgRx?
NgRx es una gran herramienta, pero no la uso en todas mis aplicaciones. ¿Por qué? Antes de empezar con NgRx, siempre me hago estas preguntas:
-
¿Mi aplicación es pequeña o es solo un MVP?
-
¿Necesito manejar estado, pero mis componentes no necesitan reaccionar a cambios en otros lados?
-
¿Mis compañeros de equipo conocen RxJS y Redux?
Si respondiste que sí, entonces no necesitas NgRx. NgRx requiere un buen conocimiento de RxJS e implica escribir bastante código repetitivo (boilerplate). Por lo tanto, si estás trabajando en algo pequeño o entregando un MVP, te recomiendo construir la solución usando servicios de Angular con BehaviorSubject o considerar @ngrx/component-store como una buena alternativa.
Pero, si este no es tu escenario y quieres avanzar con NgRx, hazte las siguientes preguntas sobre tu estado:
-
¿Lo consumen muchos componentes y servicios?
-
¿Es persistente y cambia a través de distintas fuentes?
-
¿Cambia por acciones provenientes de otros lugares?
-
¿Necesita estar sincronizado o disponible para las rutas?
-
¿Se obtiene a través de un efecto secundario (side effect)?
Si la mayoría de estas respuestas son afirmativas, entonces sí necesitas usar NgRx. La mejor manera de entender si realmente lo necesitas es con un ejemplo real: la web de NBA.com. Tiene muchísimas interacciones del usuario, necesita mantener el estado en el router, sincronizar componentes, reaccionar a cambios en el feed en tiempo real y manejar puntos como:
-
La URL está vinculada con el estado del calendario y los filtros.
-
Los calendarios filtran la información y el usuario puede cambiarlos, lo cual también actualiza la URL.
-
El feed de partidos debe reaccionar a cambios en tiempo real.

Cuando el usuario realiza muchas interacciones y los componentes deben reaccionar a múltiples fuentes de datos, NgRx ofrece un conjunto de librerías como @ngrx/store, @ngrx/effects, @ngrx/router-store, @ngrx/entity, @ngrx/component-store, @ngrx/signals y @ngrx/operators. Estas herramientas nos ayudan a construir un estado global y reactivo aislando los efectos secundarios, integrándose con el router de Angular, gestionando colecciones de entidades y ofreciendo una forma muy sencilla de depurar usando Redux DevTools.
NgRx facilita organizar y manejar el estado porque sigue el patrón REDUX, por lo que tenemos:
-
Una única fuente de la verdad: el
store. -
El estado es de solo lectura: la única forma de modificarlo es despachando acciones.
-
Los reducers son funciones puras responsables de cambiar el estado.
-
Ofrece Selectors para obtener partes específicas del estado.
Todas estas piezas siguen un flujo de trabajo claro, donde cada una cumple una responsabilidad específica en el proceso. Veamos cómo funciona este flujo en NgRx.
Flujo de trabajo en NgRx
Por ejemplo, en mi aplicación de Angular, el componente home.component requiere que el usuario acepte los términos y condiciones. Luego de aceptarlos, el usuario navega a la página About. Sin embargo, cuando regresa a Home, la casilla de verificación vuelve a aparecer desmarcada 🙃.
¿Por qué mi aplicación no mantiene el estado?
El motivo es que el componente home.component se destruyó al navegar a About y el estado desapareció con él, ya que no se estaba guardando en ningún lugar. Me parece un caso sencillo y perfecto para resolver con NgRx y mostrar cómo funciona su flujo de trabajo.
Sí, es un caso muy fácil de resolver con un BehaviorSubject, pero es la forma más clara de mostrar el flujo de trabajo de NgRx.
El flujo de NgRx se basa en Actions, Reducers, Store y Selectors (junto con Effects cuando son necesarios):
-
El componente dispara una acción:
[TermsCondition Page] Accept Terms Conditions. -
El
reducerrecibe la acción disparada, toma una copia delstateactual, aplica los cambios y actualiza el estado. -
El componente lee el cambio en el estado a través de los
selectorso directamente desde elstoreglobal.

Configuración del proyecto
En lugar de construir una aplicación desde cero, preparé un repositorio como punto de partida. En este ejemplo uso Angular con componentes Standalone (sin módulos).
Primero, abre tu terminal y ejecuta los siguientes comandos para clonar el repositorio e instalar las dependencias:
git clone https://github.com/danywalls/start-with-ngrx.git
npm iLuego, ejecuta ng serve para iniciar la aplicación de ejemplo y abre tu navegador en http://localhost:4200. En la página de inicio, marca la casilla de verificación. Después, haz clic en "About" y vuelve a "Home". Verás que la casilla vuelve a estar desmarcada.

Ya tenemos el escenario listo, ¡es momento de solucionarlo usando NgRx! ⚒️
Configurar NgRx
Ahora instalamos NgRx ejecutando el comando npm i @ngrx/store:
npm i @ngrx/storeAbre el archivo app.config.ts. En la sección de proveedores (providers), usa la función provideStore para configurar el estado global. Esta función espera el estado y el reducer, pero como todavía no tenemos el reducer listo, la inicializamos vacía por ahora:
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
import { provideStore } from '@ngrx/store';
export const appConfig = {
providers: [provideRouter(routes), provideStore()],
};Ahora necesitamos definir el estado para la página de inicio. Crea un nuevo archivo en pages/home/home.state.ts. Dentro, crea una interfaz para HomeState y define el initialState:
El estado es un objeto con las propiedades que queremos exponer.
export interface HomeState {
acceptTerms: boolean
}
const initialState: HomeState = {
acceptTerms: false,
}Con el estado listo, creamos el reducer en pages/home/state/home.reducer.ts. Importa la función createReducer junto con el initialState e importa la función on.
También importa la función createAction para definir la acción. Pasa el nombre de la acción [Home Page] Accept Terms y la función que actualiza el estado.
Usa el operador spread (...) para mantener los valores actuales del state y actualizar la propiedad acceptTerms.
El código final queda así:
import { createAction, createReducer, on } from '@ngrx/store';
import { initialState } from './home.state';
export const homeReducer = createReducer(
initialState,
on(createAction('[Home Page] Accept Terms'), (state) => ({
...state,
acceptTerms: !state.acceptTerms,
})),
);Ya podemos inicializar el store. Abre de nuevo el archivo app.config.ts y agrega el slice de home al store usando homeReducer:
Otra alternativa moderna es usar provideState.
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
import {provideStore, StoreModule} from "@ngrx/store";
import {homeReducer} from "./pages/home/state/home.reducer";
export const appConfig = {
providers: [provideRouter(routes),
provideStore(
{
home: homeReducer,
}
)
]
};Usar NgRx en el componente
Estamos en los pasos finales. Primero, abre el archivo home.component.ts e inyecta el Store. Luego, obtenemos $acceptTerms desde el store. Para este artículo no voy a entrar en los selectors, así que me suscribo directamente al store usando select y transformo el observable en una señal mediante la función toSignal, evitando tener que suscribirme con el pipe async.
Hacemos un pequeño cambio en el método onChange. Con el store, despachamos la acción para disparar la actualización en el reducer.
El código final se ve así:
export class HomeComponent {
private _store = inject(Store);
public $acceptTerms = toSignal(this._store.select((state) => state.home.acceptTerms))
onChange() {
this._store.dispatch({
type: '[Home Page] Accept Terms'
})
}
}En la plantilla, actualizamos la lógica para usar la señal $acceptTerms leyendo su valor con ():
@if(!$acceptTerms()) {
<h3>Do you want to use NgRx?</h3>
<input (change)="onChange()" [value]="$acceptTerms()" type="checkbox" >
} @else {
<h2>Thanks for love NgRx🎉🥳</h2>
}Guarda los cambios y ¡listo! 🎉🎉🎉 NgRx ya está configurado y el estado queda integrado en nuestra aplicación.

Conclusión
Vimos lo sencillo que es crear un estado, una acción y un reducer, además de leer el estado directamente con el store. Para una aplicación pequeña puede sentirse como demasiado código repetitivo, pero es un excelente punto de partida para entender NgRx.
También revisamos cuándo conviene usar NgRx en lugar de servicios de Angular. Puedes usar las preguntas de la lista para decidir si tu proyecto realmente lo necesita.
Con este ejemplo práctico vimos cómo configurar NgRx para manejar el estado: configurar el store, crear el estado inicial, definir reducers e integrarlo en un componente para mantener el estado entre navegaciones.
Modern frontend development — Angular, React, TypeScript, accessibility, and performance.
Preguntas Frecuentes
¿Cuándo debería usar NgRx en lugar de servicios de Angular con BehaviorSubject para manejar el estado?
Deberías considerar NgRx cuando tu aplicación tiene un estado compartido entre muchos componentes y servicios, se actualiza desde múltiples fuentes, necesita sincronizarse con la URL o involucra efectos secundarios complejos como llamadas a APIs. Para aplicaciones pequeñas o MVPs, los servicios de Angular con BehaviorSubject son más simples y requieren mucho menos código repetitivo.
¿Cuáles son los bloques principales de NgRx y cómo interactúan entre sí?
NgRx se basa en cuatro conceptos clave: las Actions describen eventos disparados desde componentes o effects, los Reducers son funciones puras que actualizan el estado según esas acciones, el Store es la única fuente de la verdad que contiene todo el estado de la aplicación, y los Selectors son funciones que obtienen partes específicas del estado. Los Effects manejan efectos secundarios asíncronos como llamadas HTTP entre las acciones y el store.
¿Es NgRx demasiado para una aplicación pequeña en Angular y cuáles son las alternativas?
Sí, NgRx puede ser excesivo para aplicaciones pequeñas o medianas porque requiere conocimientos de RxJS y patrones Redux, además de implicar bastante código repetitivo (boilerplate). Buenas alternativas incluyen servicios de Angular con BehaviorSubject para estados compartidos simples, o el NgRx Component Store oficial, que ofrece una solución más liviana y acotada al componente sin toda la sobrecarga de Redux.
Artículos Relacionados
Cómo depurar NgRx usando Redux DevTools en Angular
Aprende a depurar el estado de NgRx en Angular moderno con Redux DevTools: configura provideStoreDevtools, rastrea acciones, inspecciona cambios y usa time-travel debugging.
Cómo manejar efectos secundarios en Angular usando NgRx Effects
Los efectos secundarios son habituales en nuestras aplicaciones. Aprende a manejarlos en Angular con NgRx Effects para evitar sobrecargar tus componentes y mantener tu estado limpio y predecible.
Cómo usar NgRx Selectors en Angular
En NgRx, cuando queremos obtener datos del store, la forma más rápida suele ser usar store.select, pero tiene riesgos de tipado. Aprende a usar Selectors para consultar el estado con tipado seguro y mejor rendimiento.
Cómo compartir datos entre componentes en Angular (Signals y servicios)
Aprende los mejores patrones para compartir datos entre componentes en Angular. Compara los decoradores clásicos Input/Output y BehaviorSubjects con las Signals modernas: input(), output(), model() y servicios basados en Signals.
Compartir este artículo
Si esta guía te resultó útil, compártela con tu equipo o con otros desarrolladores.
Software real. Lecciones reales.
Comparto las lecciones que aprendí por las malas, para que puedas evitarlas o estar preparado cuando ocurran.
Únete a 13,800+ desarrolladores y lectores.
Cero spam. Cancela tu suscripción en cualquier momento.