51 lines
1.8 KiB
TypeScript
51 lines
1.8 KiB
TypeScript
import { useEffect, useLayoutEffect, useRef } from "react";
|
|
import ReconnectingEventSource from "reconnecting-eventsource";
|
|
import { devlog } from "../utils";
|
|
|
|
|
|
export function useSSESubscription<T>({ enabled = true, url, onNewData, onDisconnect, marker = "" }: {
|
|
enabled?: boolean;
|
|
url: string;
|
|
onNewData: (data: T[]) => void;
|
|
onDisconnect?: () => void;
|
|
marker?: string;
|
|
}) {
|
|
const onNewDataRef = useRef(onNewData);
|
|
const onDisconnectRef = useRef(onDisconnect);
|
|
|
|
useLayoutEffect(() => {
|
|
onNewDataRef.current = onNewData;
|
|
onDisconnectRef.current = onDisconnect;
|
|
}, [onNewData, onDisconnect]);
|
|
|
|
useEffect(() => {
|
|
if (!enabled) return;
|
|
|
|
const eventSource = new ReconnectingEventSource(url);
|
|
|
|
eventSource.addEventListener("open", () => devlog(`EventSource connected with ${url}`));
|
|
eventSource.addEventListener("close", () => devlog(`EventSource closed with ${url}`));
|
|
eventSource.addEventListener("message", event => {
|
|
try {
|
|
console.log("EVENT")
|
|
console.log(event)
|
|
if (!JSON.stringify(event).includes('"event":"ping"') && !JSON.stringify(event).includes("'event':'ping'")) {
|
|
const newData = JSON.parse(event.data) as T;
|
|
devlog(`new SSE: ${marker}`, newData);
|
|
onNewDataRef.current([newData]);
|
|
}
|
|
} catch (error) {
|
|
devlog(`SSE parsing error: ${marker}`, event.data, error);
|
|
}
|
|
});
|
|
eventSource.addEventListener("error", event => {
|
|
devlog("SSE Error:", event);
|
|
});
|
|
|
|
return () => {
|
|
eventSource.close();
|
|
onDisconnectRef.current?.();
|
|
};
|
|
}, [enabled, marker, url]);
|
|
}
|