Probar Estrategias de Sincronización de Estado

Quiz
15 min~5 min lectura

Quiz Interactivo

Pon a prueba tus conocimientos

Concepto clave

La sincronización de estado en micro-frontends con Module Federation es el proceso de mantener consistencia en datos compartidos entre aplicaciones independientes que se ejecutan en el mismo contexto del navegador. Imagina un centro comercial donde cada tienda (micro-frontend) tiene su propio inventario, pero todas necesitan conocer las promociones globales del centro. Sin sincronización, una tienda podría mostrar una promoción que ya expiró en otra.

El desafío principal es que cada micro-frontend es un bundlo independiente con su propio estado, pero ciertos datos (como autenticación del usuario, preferencias de tema, o carrito de compras) deben ser consistentes. Module Federation permite compartir código, pero no gestiona automáticamente el estado compartido. Aquí entran estrategias como eventos personalizados, observables, o librerías de estado global.

Cómo funciona en la práctica

Un enfoque común es usar un event bus basado en CustomEvents del DOM. Cada micro-frontend publica eventos cuando su estado cambia, y los otros se suscriben para actualizarse. Por ejemplo, en un e-commerce, el micro-frontend de "Productos" publica un evento cuando un item se añade al carrito, y el micro-frontend de "Carrito" lo escucha para reflejar el cambio.

Paso a paso: 1) Define un contrato de eventos (ej., "cart-updated") con una estructura de datos clara. 2) En el micro-frontend emisor, despacha un CustomEvent con los datos. 3) En los micro-frontends receptores, añade event listeners. 4) Usa Module Federation para compartir la lógica del event bus si es necesario, evitando duplicación. Esto mantiene un acoplamiento bajo, ya que los micro-frontends solo se comunican a través de eventos, no referencias directas.

Codigo en accion

Antes: Sin sincronización, cada micro-frontend maneja su estado aislado, llevando a inconsistencias.

// En micro-frontend A (Productos)
let cart = [];
function addToCart(product) {
    cart.push(product);
    // Solo actualiza localmente, el carrito en otro MF no cambia
}

// En micro-frontend B (Carrito)
let cart = []; // Estado duplicado y desincronizado

Después: Implementando un event bus para sincronización.

// shared/eventBus.js - Compartido via Module Federation
export const eventBus = {
    listeners: {},
    on(event, callback) {
        if (!this.listeners[event]) this.listeners[event] = [];
        this.listeners[event].push(callback);
    },
    emit(event, data) {
        if (this.listeners[event]) {
            this.listeners[event].forEach(cb => cb(data));
        }
        // También despachar CustomEvent para comunicación cross-origin si es necesario
        window.dispatchEvent(new CustomEvent(event, { detail: data }));
    }
};

// En micro-frontend A (Productos)
import { eventBus } from 'shared/eventBus';
let cart = [];
function addToCart(product) {
    cart.push(product);
    eventBus.emit('cart-updated', { cart: cart }); // Publica el cambio
}

// En micro-frontend B (Carrito)
import { eventBus } from 'shared/eventBus';
let cart = [];
eventBus.on('cart-updated', (data) => {
    cart = data.cart; // Sincroniza el estado
    updateUI();
});

Errores comunes

  • Eventos sin contrato claro: Publicar eventos con estructuras de datos inconsistentes causa errores. Solución: Define y documenta un esquema (ej., con TypeScript) para los datos del evento.
  • Falta de manejo de ciclos de vida: No remover event listeners al desmontar componentes, llevando a fugas de memoria. Usa hooks como useEffect en React o lifecycle methods para limpiar.
  • Sincronización excesiva: Emitir eventos por cada cambio de estado menor puede degradar el rendimiento. Optimiza con debouncing o agregando cambios.
  • Ignorar concurrencia: En aplicaciones complejas, cambios simultáneos pueden causar condiciones de carrera. Usa mecanismos como locks o versionado del estado.
  • Depender de orden de carga: Asumir que un micro-frontend se carga antes que otro, llevando a eventos perdidos. Implementa un buffer de eventos o un estado inicial compartido.

Checklist de dominio

  1. ¿Has definido un contrato explícito para eventos de sincronización de estado?
  2. ¿Usas un event bus compartido o CustomEvents para comunicación entre micro-frontends?
  3. ¿Manejas adecuadamente la suscripción y limpieza de listeners para evitar fugas?
  4. ¿Has optimizado la frecuencia de emisión de eventos para rendimiento?
  5. ¿Consideras estrategias para estados iniciales y eventos perdidos durante la carga?
  6. ¿Documentas las dependencias de estado compartido entre equipos?
  7. ¿Pruebas escenarios de concurrencia y fallos en la sincronización?

Implementar un Sistema de Sincronización de Tema entre Micro-frontends

En este ejercicio, crearás un sistema para sincronizar el tema (claro/oscuro) entre dos micro-frontends independientes usando Module Federation y un event bus.

  1. Configuración inicial: Crea dos aplicaciones React simples (MF1 y MF2) con Module Federation. Comparte un archivo shared/eventBus.js desde MF1.
  2. Implementa el event bus: En shared/eventBus.js, define un objeto con métodos on y emit que use CustomEvents. Asegúrate de exportarlo.
  3. Estado local: En MF1, añade un botón que cambie el tema entre 'light' y 'dark'. Guarda el tema en el estado local de React.
  4. Publicar eventos: Cuando el tema cambie en MF1, usa eventBus.emit('theme-changed', { theme: newTheme }).
  5. Suscribir y sincronizar: En MF2, importa el event bus y suscríbete al evento 'theme-changed'. Actualiza el estado local de MF2 para reflejar el tema.
  6. Prueba: Ejecuta ambas aplicaciones, cambia el tema en MF1 y verifica que MF2 se actualice automáticamente.
  7. Mejora: Añade persistencia del tema en localStorage y maneja la carga inicial sincronizada.
Pistas
  • Usa window.dispatchEvent para eventos globales si el event bus no funciona entre orígenes.
  • Considera usar un contexto de React para el tema en cada MF para facilitar la actualización de la UI.
  • Añade un listener en el event bus para eventos durante la carga, almacenándolos en un buffer si es necesario.

Evalua tu comprension

Completa el quiz interactivo de arriba para ganar XP.