Gestión del Estado: Contexto y Zustand
Streamlyra utiliza una arquitectura híbrida para la gestión del estado, eligiendo la herramienta adecuada según el tipo de datos y la frecuencia de actualización.
AuthProvider (React Context)
El AuthProvider gestiona la identidad y sesión del usuario. Dado que los datos de autenticación cambian poco frecuentemente, React Context es ideal por su simplicidad. Utiliza localStorage para persistir la sesión.
Funcionalidades principales
- Persistencia: Mantiene al usuario conectado entre recargas de página.
- Autenticación en Tiempo Real: Valida el token con el servidor al iniciar.
- Blindaje de Sesión (
isLoggingOut): Utiliza una referencia interna para bloquear re-autenticaciones accidentales durante el proceso de salida, evitando el bug de "auto-re-login". - Hook:
useAuth: Provee acceso auser,status,isAuthenticatedy funciones delogin/logout. - Logout Atómico: Realiza la limpieza local inmediata (localStorage, state, navigate) y notifica al servidor en segundo plano para garantizar una respuesta instantánea.
Arquitectura de Flujo de Datos
El siguiente diagrama ilustra cómo fluyen los datos desde el servidor hasta los componentes de la interfaz, pasando por los mecanismos de sincronización y los stores de estado global.
Zustand Stores (Alta Frecuencia)
Para datos en tiempo real y componentes que requieren actualizaciones rápidas sin re-renders masivos, hemos migrado a Zustand. Estos son los archivos centrales:
1. src/store/useConnectionsStore.ts
Es el orquestador del estado de las plataformas conectadas.
- Estado Atómico: Almacena un mapa de
connectionsStatusyconnectionsStatsindexados por plataforma. - Selectores Memorizados: Los componentes usan
useShallowy selectores granulares para escuchar cambios solo en las propiedades que necesitan (ej: solo el conteo de espectadores de Twitch). - Desconexión Optimista (Optimistic UI): Al desvincular una plataforma, el store limpia localmente el estado de forma inmediata. Esto hace que la plataforma desaparezca visualmente al instante sin esperar la confirmación de red, mejorando la fluidez percibida.
- Consistencia de Datos: Al recibir datos de la API (polling), el store mezcla la información con los eventos de tiempo real del Socket, priorizando los estados transitorios (como
searching) para evitar que la UI retroceda a estados "Offline" erróneamente. - Hash de Conexión: Mantiene un
connectionHashcalculado que permite a hooks comouseSocketreaccionar a cambios estructurales en las conexiones sin depender de la referencia del objeto.
2. src/store/useChatStore.ts
Gestiona la memoria y el flujo de mensajes simultáneos con alto rendimiento.
- Mecanismo de Flush/Batching: Los mensajes se acumulan en un buffer temporal y se "vuelcan" al estado principal cada 300ms. Esto previene que el hilo principal se bloquee durante ráfagas intensas de chat.
- Acciones de Moderación Global: Permite eliminar mensajes o banear usuarios de forma atómica. Al eliminar un mensaje en el store, todos los componentes suscritos reflejan el cambio instantáneamente.
- Optimización de Memoria (MAX_MESSAGES): Implementa una limpieza automática (trimming) para mantener el arreglo de mensajes dentro de un límite (ej. 1000 mensajes), evitando fugas de memoria en sesiones largas.
- Hook
useChatMessages: Recientemente refactorizado de un manejador de estado independiente de React a un "thin proxy" que encapsula llamadas auseChatStoreusandouseShallow. Mantiene compatibilidad hacia atrás en los componentes antiguos, pero se orienta íntegramente al rendimiento centralizado de Zustand.
Beneficios de la Arquitectura con Zustand
- Rendimiento Extremo: Eliminación del "Context Hell". Un mensaje de chat ya no provoca que se refresque la barra de herramientas o el buscador.
- Lógica Desacoplada: Los hooks como
useConnectionsSocketenvían datos directamente a los stores sin necesidad de pasar por la pirámide de componentes de React. - Estado Predictible: Al centralizar la lógica en stores puramente de TypeScript, el comportamiento ante errores y estados complejos es más fácil de depurar.
DialogProvider (lib/dialog)
Provee una interfaz imperativa para mostrar diálogos de confirmación en toda la aplicación mediante dialogService, evitando la necesidad de declarar estados "open/close" en cada página.