← back to Dw Boardroom V2

frontend/src/hooks/useWebSocket.ts

55 lines

import { useState, useEffect, useRef, useCallback } from 'react';
import type { WSEvent } from '../types';

const WS_URL = `ws://${window.location.host}/ws`;
const MAX_EVENTS = 200;

export function useWebSocket() {
  const [events, setEvents] = useState<WSEvent[]>([]);
  const [connected, setConnected] = useState(false);
  const wsRef = useRef<WebSocket | null>(null);
  const reconnectTimer = useRef<number>();

  const connect = useCallback(() => {
    if (wsRef.current?.readyState === WebSocket.OPEN) return;

    try {
      const ws = new WebSocket(WS_URL);
      wsRef.current = ws;

      ws.onopen = () => {
        setConnected(true);
        if (reconnectTimer.current) clearTimeout(reconnectTimer.current);
      };

      ws.onmessage = (evt) => {
        try {
          const event: WSEvent = JSON.parse(evt.data);
          setEvents(prev => [...prev.slice(-MAX_EVENTS), event]);
        } catch {}
      };

      ws.onclose = () => {
        setConnected(false);
        reconnectTimer.current = window.setTimeout(connect, 3000);
      };

      ws.onerror = () => {
        ws.close();
      };
    } catch {}
  }, []);

  useEffect(() => {
    connect();
    return () => {
      if (wsRef.current) wsRef.current.close();
      if (reconnectTimer.current) clearTimeout(reconnectTimer.current);
    };
  }, [connect]);

  const clearEvents = useCallback(() => setEvents([]), []);

  return { events, connected, clearEvents };
}