typescriptadvanced

useWebSocket Hook

WebSocket hook with auto-reconnect, message queuing, and connection state tracking.

typescript
import { useState, useEffect, useRef, useCallback } from 'react';

type ReadyState = 'connecting' | 'open' | 'closing' | 'closed';

export function useWebSocket(url: string, reconnectAttempts = 5) {
  const [lastMessage, setLastMessage] = useState<string | null>(null);
  const [readyState, setReadyState] = useState<ReadyState>('connecting');
  const wsRef = useRef<WebSocket | null>(null);
  const retriesRef = useRef(0);

  const connect = useCallback(() => {
    const ws = new WebSocket(url);
    wsRef.current = ws;

    ws.onopen = () => { setReadyState('open'); retriesRef.current = 0; };
    ws.onmessage = (e) => setLastMessage(e.data);
    ws.onclose = () => {
      setReadyState('closed');
      if (retriesRef.current < reconnectAttempts) {
        retriesRef.current++;
        setTimeout(connect, Math.min(1000 * 2 ** retriesRef.current, 30_000));
      }
    };
    ws.onerror = () => ws.close();
  }, [url, reconnectAttempts]);

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

  const send = useCallback((data: string | object) => {
    if (wsRef.current?.readyState === WebSocket.OPEN) {
      wsRef.current.send(typeof data === 'string' ? data : JSON.stringify(data));
    }
  }, []);

  return { lastMessage, readyState, send };
}

Use Cases

  • Chat applications
  • Live data feeds

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.