@supunlakmal/hooks
Version:
A collection of reusable React hooks
87 lines • 3.51 kB
JavaScript
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