Skip to content

Gestión de estado en Angular

La gestión de estado consiste en organizar la información que necesita una aplicación para funcionar: datos de usuario, filtros, formularios, resultados de API, preferencias y estados de carga o error.

Conceptos clave

  • Estado local: información que solo necesita un componente.
  • Estado compartido: información usada por varios componentes.
  • Estado derivado: valores calculados a partir de otros datos.
  • Servicios: mecanismo habitual para compartir estado en Angular.
  • Observables: flujos de datos que permiten reaccionar a cambios.
  • Signals: primitiva moderna para representar valores reactivos.

Estado local

El estado local debe quedarse dentro del componente cuando no lo necesita nadie más.

typescript
export class ContadorComponent {
  contador = 0;

  incrementar(): void {
    this.contador++;
  }
}
html
<button (click)="incrementar()">Incrementar</button>
<p>Valor: {{ contador }}</p>

Estado compartido con servicios

Cuando varios componentes necesitan los mismos datos, conviene mover el estado a un servicio.

typescript
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class UsuarioStateService {
  private readonly usuarioSubject = new BehaviorSubject<string | null>(null);
  readonly usuario$ = this.usuarioSubject.asObservable();

  setUsuario(nombre: string): void {
    this.usuarioSubject.next(nombre);
  }

  limpiarUsuario(): void {
    this.usuarioSubject.next(null);
  }
}

Estado de carga y error

Las pantallas que consumen APIs deberían representar al menos tres estados:

  • Cargando: la petición está en curso.
  • Error: la petición falló.
  • Datos: la petición terminó correctamente.
typescript
type EstadoVista<T> =
  | { status: 'loading' }
  | { status: 'error'; message: string }
  | { status: 'success'; data: T };

Ejemplo práctico

typescript
export class ProductosComponent {
  estado: EstadoVista<Producto[]> = { status: 'loading' };

  constructor(private productosService: ProductosService) {}

  ngOnInit(): void {
    this.productosService.getProductos().subscribe({
      next: (data) => this.estado = { status: 'success', data },
      error: () => this.estado = {
        status: 'error',
        message: 'No se pudieron cargar los productos'
      }
    });
  }
}

Buenas prácticas

  • Mantén el estado cerca de donde se usa.
  • Usa servicios para estado compartido.
  • Evita duplicar la misma información en varios componentes.
  • Representa estados de carga y error.
  • No mezcles lógica de presentación con lógica de negocio.
  • Limpia suscripciones cuando no uses async pipe o mecanismos automáticos.

Errores comunes

  • Convertir todo en estado global.
  • Guardar datos derivados que pueden calcularse.
  • No gestionar errores de API.
  • Mutar objetos compartidos sin control.
  • Hacer llamadas repetidas a la misma API desde varios componentes.

Chuleta rápida

txt
Componente = estado local
Servicio = estado compartido
Observable = flujo reactivo
Loading/Error/Data = estados mínimos de vista

Recursos relacionados