59 lines
1.4 KiB
TypeScript
59 lines
1.4 KiB
TypeScript
import { useEffect, useRef, useState, useCallback } from "react";
|
|
import { getApi } from "./useApi";
|
|
|
|
interface ItemSseHandlers {
|
|
onEvent: (data: any) => void;
|
|
onOpen?: () => void;
|
|
onError?: (evt: Event) => void;
|
|
}
|
|
|
|
interface ItemSseResult {
|
|
connected: boolean;
|
|
events: any[];
|
|
}
|
|
|
|
export function useItemSse(url: string | null, handlers: ItemSseHandlers): ItemSseResult {
|
|
const [connected, setConnected] = useState(false);
|
|
const [events, setEvents] = useState<any[]>([]);
|
|
const handlersRef = useRef(handlers);
|
|
handlersRef.current = handlers;
|
|
|
|
useEffect(() => {
|
|
if (!url) return;
|
|
|
|
const api = getApi();
|
|
const baseUrl = (api.defaults.baseURL ?? "").replace(/\/+$/, "");
|
|
const fullUrl = baseUrl + url;
|
|
const es = new EventSource(fullUrl);
|
|
|
|
es.onopen = () => {
|
|
setConnected(true);
|
|
handlersRef.current.onOpen?.();
|
|
};
|
|
|
|
es.onmessage = (e) => {
|
|
try {
|
|
const data = JSON.parse(e.data);
|
|
setEvents((prev) => [...prev, data]);
|
|
handlersRef.current.onEvent(data);
|
|
} catch {
|
|
// ignore malformed JSON
|
|
}
|
|
};
|
|
|
|
es.onerror = (e) => {
|
|
setConnected(false);
|
|
handlersRef.current.onError?.(e);
|
|
};
|
|
|
|
return () => {
|
|
es.close();
|
|
setConnected(false);
|
|
};
|
|
}, [url]);
|
|
|
|
const clearEvents = useCallback(() => setEvents([]), []);
|
|
|
|
return { connected, events };
|
|
}
|