🇺🇸 EN
Frontend
·6 min read·↗·🇺🇸 EN

Cómo depurar NgRx usando Redux DevTools en Angular

Portada principal del artículo: Cómo depurar NgRx usando Redux DevTools en Angular

Cuando gestiono estados complejos en aplicaciones de Angular, nada me quita más productividad que intentar adivinar por qué cambió una parte del estado de repente o por qué un selector emitió datos inesperados.

Llenar mis reducers y componentes de console.log() es lento, ensucia el código y no ofrece visibilidad sobre el historial de las acciones despachadas.

Con Redux DevTools y @ngrx/store-devtools, obtienes inspección en tiempo real, comparación visual de cambios (diffing), rastreo de la pila de llamadas y depuración con time travel directamente en tu navegador.


Console.log vs. Redux DevTools: por qué importan las herramientas ⚡

CaracterísticaDepuración con console.log()Redux DevTools con NgRx
Historial de accionesLogs manuales, se pierden al recargar la páginaLínea de tiempo cronológica completa
Diferencias de estadoDifícil de comparar objetos anidados profundosÁrbol JSON visual con código de colores y diff
Time TravelImposibleAvanzar y retroceder a través de las acciones
Rastreo de la acciónRequiere breakpoints manualesRastreo automático de archivo y número de línea
Seguridad en producciónAlto riesgo de filtrar logsFácil de alternar mediante isDevMode()

1. Instalación de @ngrx/store-devtools 📦

En aplicaciones modernas de Angular (Angular 17, 18, 19+), instalo el paquete oficial de las devtools del store con este comando:

npm install @ngrx/store-devtools

2. Configurar provideStoreDevtools en Angular Standalone 🛠️

Angular utiliza la configuración de aplicaciones standalone en app.config.ts. Para habilitar las devtools, uso provideStoreDevtools().

Esta es la configuración recomendada y lista para producción que suelo utilizar:

// app.config.ts
import { ApplicationConfig, isDevMode } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideStore } from '@ngrx/store';
import { provideStoreDevtools } from '@ngrx/store-devtools';
import { routes } from './app.routes';
import { homeReducer } from './pages/home/state/home.reducer';
 
export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    provideStore({
      home: homeReducer,
    }),
    provideStoreDevtools({
      maxAge: 25, // Mantiene los últimos 25 estados
      logOnly: !isDevMode(), // Restringe la extensión a solo lectura en producción
      autoPause: true, // Pausa la grabación de acciones cuando la ventana pierde el foco
      trace: true, // Si es true, incluye el stack trace para cada acción
      traceLimit: 25, // Límite de llamadas en el stack trace a capturar
      connectInZone: true, // Asegura que la extensión corra dentro de la zona de Angular
    }),
  ],
};

[!TIP] Configurar logOnly: !isDevMode() asegura que los usuarios no puedan modificar el estado de tu aplicación en producción mediante el panel de DevTools, manteniendo al mismo tiempo capacidades seguras de diagnóstico.


3. Instalar la extensión del navegador 🔌

Para ver tu store e interactuar con él, instala la extensión de Redux DevTools en tu navegador:

Una vez instalada, inicia tu servidor de desarrollo:

npm run dev

Abre las Chrome DevTools (F12 o Cmd + Option + I en macOS) y haz clic en la pestaña Redux. Verás la acción inicial @ngrx/store/init registrada de inmediato:


4. Acciones despachadas y reducers en la práctica 🔄

Veamos cómo se rastrean los cambios de estado a través de las acciones. Supongamos que tengo un reducer que gestiona la aceptación de términos:

// home.reducer.ts
import { createAction, createReducer, on } from '@ngrx/store';
import { initialState } from './home.state';
 
export const acceptTerms = createAction('[Home Page] Accept Terms');
export const rejectTerms = createAction('[Home Page] Reject Terms');
 
export const homeReducer = createReducer(
  initialState,
  on(acceptTerms, (state) => ({
    ...state,
    acceptTerms: true,
  })),
  on(rejectTerms, (state) => ({
    ...state,
    acceptTerms: false,
  })),
);

En mi componente, despacho las acciones y conecto el estado usando Signals de Angular y el nuevo control flow:

// home.component.ts
import { Component, inject } from '@angular/core';
import { Store } from '@ngrx/store';
import { acceptTerms, rejectTerms } from './state/home.actions';
import { selectAcceptTerms } from './state/home.selectors';
 
@Component({
  selector: 'app-home',
  standalone: true,
  template: `
    <div class="terms-card">
      @if (!acceptTerms()) {
        <h3>Do you agree to use NgRx for state management?</h3>
        <button class="btn btn-primary" (click)="onAccept()">
          Accept Terms
        </button>
      } @else {
        <h2>Thanks for choosing NgRx! 🎉</h2>
        <button class="btn btn-secondary" (click)="onReject()">
          Reject Terms
        </button>
      }
    </div>
  `,
})
export class HomeComponent {
  private store = inject(Store);
  acceptTerms = this.store.selectSignal(selectAcceptTerms);
 
  onAccept() {
    this.store.dispatch(acceptTerms());
  }
 
  onReject() {
    this.store.dispatch(rejectTerms());
  }
}

5. Rastreo de acciones y depuración con Time Travel ⏱️

Cuando haces clic en los botones de la interfaz, cada acción queda registrada en la línea de tiempo de DevTools:

Pestañas clave en Redux DevTools

  1. Pestaña Action: Inspecciona el tipo y la carga útil (payload) de la acción despachada.
  2. Pestaña Diff: Resalta con exactitud qué propiedades del store cambiaron (verde para adiciones, rojo para eliminaciones).
  3. Pestaña State: Muestra un árbol interactivo con el estado global completo en ese milisegundo exacto.
  4. Pestaña Trace: Haz clic en cualquier acción para ver la pila de llamadas (stack trace) de TypeScript que apunta directo a home.component.ts:32.
  5. Barra de Time Travel (barra inferior): Arrastra el control deslizante hacia atrás o haz clic en Jump en una acción anterior. La interfaz se actualiza de inmediato para reflejar ese estado histórico sin necesidad de recargar la página.

Buenas prácticas de seguridad para producción 🔒

Antes de desplegar a producción, te recomiendo seguir estas reglas:

  1. Nunca expongas las devtools completas en producción: Usa logOnly: !isDevMode().
  2. Limpia campos sensibles: Si tu estado maneja tokens de autenticación, contraseñas o datos personales sensibles, configura actionSanitizer y stateSanitizer:
provideStoreDevtools({
  maxAge: 25,
  logOnly: !isDevMode(),
  actionSanitizer: (action) => 
    action.type === '[Auth] Login Success' 
      ? { ...action, payload: { ...action.payload, token: '***REDACTED***' } } 
      : action,
})

Resumen 🎯

Integrar Redux DevTools en tu flujo de trabajo con Angular y NgRx cambia por completo la experiencia de depuración, dejando atrás las suposiciones:

  • Configúralo una sola vez en app.config.ts con provideStoreDevtools.
  • Inspecciona acciones, mutaciones de estado y pilas de llamadas sin llenar tu consola de ruido.
  • Reproduce casos límite complicados en segundos usando time-travel debugging.

Si quieres conocer más buenas prácticas de arquitectura en Angular, revisa mis guías relacionadas:

Parte de la serie Frontend

Modern frontend development — Angular, React, TypeScript, accessibility, and performance.

Ver serie completa

Preguntas Frecuentes

¿Cómo configuro Redux DevTools con NgRx standalone en Angular moderno?

Importa provideStoreDevtools desde @ngrx/store-devtools y regístralo dentro del arreglo providers de tu archivo app.config.ts junto a provideStore. Configura opciones clave como maxAge y logOnly: !isDevMode().

¿Qué te permite hacer la función de time travel en Redux DevTools?

Time travel te permite avanzar y retroceder por cada acción despachada en tu aplicación, reproduciendo los cambios de estado para reproducir errores al instante sin recargar la página.

¿Cómo debo configurar NgRx Store DevTools para compilaciones de producción?

Configura siempre logOnly: !isDevMode() o define maxAge: 25 de forma condicional para evitar exponer datos sensibles del estado en el navegador y eliminar el consumo innecesario de memoria en producción.

¿Puede Redux DevTools rastrear en qué parte del código se despachó una acción de NgRx?

Sí. Al configurar trace: true y traceLimit: 25 en provideStoreDevtools, se captura la pila de llamadas exacta de TypeScript, apuntando directamente al método que disparó la acción.

Artículos Relacionados

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.

User avatar
User avatar
User avatar
User avatar
+13K

Únete a 13,800+ desarrolladores y lectores.

Cero spam. Cancela tu suscripción en cualquier momento.