UNPKG

@supunlakmal/hooks

Version:

A collection of reusable React hooks

87 lines 3.51 kB
import { useState, useEffect, useRef } from 'react'; /** * Custom hook to connect to a Server-Sent Events (SSE) endpoint. * * @param url The URL of the SSE endpoint. * @param options Configuration options for the connection. * @returns An object with connection status, last message, error, and close function. */ export function useEventSource(url, options = {}) { const { withCredentials = false, eventListeners = {} } = options; const [status, setStatus] = useState('closed'); const [lastMessage, setLastMessage] = useState(null); const [error, setError] = useState(null); const eventSourceRef = useRef(null); const listenersRef = useRef(eventListeners); // Ref to keep listeners stable // Update listeners ref if options.eventListeners changes useEffect(() => { listenersRef.current = eventListeners; }, [eventListeners]); const close = () => { if (eventSourceRef.current) { eventSourceRef.current.close(); eventSourceRef.current = null; setStatus('closed'); // console.log('EventSource explicitly closed'); } }; useEffect(() => { if (!url || typeof window === 'undefined') { setStatus('closed'); return; } setStatus('connecting'); setError(null); setLastMessage(null); try { const es = new EventSource(url, { withCredentials }); eventSourceRef.current = es; es.onopen = () => { setStatus('open'); // console.log('EventSource connection opened'); }; es.onmessage = (event) => { setLastMessage(event); // Optionally try to parse data // try { // const parsedData = JSON.parse(event.data); // setLastMessage({ ...event, data: parsedData }); // } catch (e) { // setLastMessage(event); // Store raw data if JSON parsing fails // } }; es.onerror = (errEvent) => { setError(errEvent); setStatus('error'); // console.error('EventSource error:', errEvent); close(); // Close on error }; // Register custom event listeners Object.entries(listenersRef.current).forEach(([eventName, handler]) => { if (es) { es.addEventListener(eventName, handler); } }); } catch (err) { console.error('Failed to create EventSource:', err); setError(null); // Set error state to null, type is Event | null setStatus('error'); eventSourceRef.current = null; } // Cleanup function return () => { // Remove custom listeners before closing if (eventSourceRef.current) { const es = eventSourceRef.current; Object.entries(listenersRef.current).forEach(([eventName, handler]) => { es.removeEventListener(eventName, handler); }); } close(); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [url, withCredentials]); // Dependencies: url, withCredentials. listenersRef handles listener changes. return { status, lastMessage, error, close }; } //# sourceMappingURL=useEventSource.js.map