Add autoConnect option and isConnected getter to EventSource
Why would you need an autoConnect option? If you want to disable the automatic reconnect, you can just set the pollingInterval to 0.
And instead of adding a new isConnected function, it would be both easier and more useful to expose the status property of the EventSource class.
Thank you for your question
I need it for create instance of eventSource without connect
then I control connection by call eventSource.open() or eventSource.close()
this small example how I use it
type tEvent = {
type: 'data' | 'error' | 'close' | 'remove';
data: string | null;
eventId : string;
}
const eventSource = new EventSource(global.serverUrl + 'serverEvents',{autoConnect: false});
function subscribeToEvent(api : string,args: string,eventId : string) {
return fetch(global.serverUrl + 'serverEvents', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({api,args,eventId}),
})
}
const listeners = new Map<string, (data :any)=> any>();
export function startListening<T>(api : string,callback : (data : T)=>void,args : any){
if(!eventSource.isConnected){
eventSource.open();
}
const eventHash = crc32.str(api +':'+ JSON.stringify(args)).toString()
const randomId = Math.random().toString(36).substring(2, 15);
const eventId = eventHash + ':' + randomId;
subscribeToEvent(api,args,eventId)
listeners.set(eventId,callback);
return () => {
listeners.delete(eventId);
if (listeners.size === 0) {
eventSource.close();
}
}
}
eventSource.addEventListener('message', (event) => {
const data : tEvent | null = event.data ? JSON.parse(event.data) : null;
if(!data) return
const {type, data: eventData, eventId} = data;
if (type === 'data') {
const callback = listeners.get(eventId);
const cache = storage.getString(eventId);
if (cache) {
callback?.(JSON.parse(cache));
}
callback?.(eventData);
} else if (type === 'error') {
console.error('Error event:', eventData);
} else if (type === 'close') {
eventSource.close();
console.log('Connection closed');
} else if (type === 'remove') {
listeners.delete(eventId);
console.log('Listener removed for eventId:', eventId);
}
})
eventSource.addEventListener('error', (event) => {
console.error('Error event:', event);
});
AppState.addEventListener('change', (state) => {
if (state === 'active') {
eventSource.open();
} else {
eventSource.close();
}
})
export function useEventSource({api, args} : {api : string, args : any}) {
const [_args, setArgs] = useState(args);
const [data, setData] = useState<any>(null);
const [eventId, setEventId] = useState<string | null>(null);
useEffect(() => {
const eventHash = crc32.str(api +':'+ JSON.stringify(args)).toString()
const randomId = Math.random().toString(36).substring(2, 15);
const eventId = eventHash + ':' + randomId;
subscribeToEvent(api,args,eventId)
listeners.set(eventId,setData);
setEventId(eventId);
return () => {
listeners.delete(eventId);
if (listeners.size === 0) {
eventSource.close();
}
}
},[_args])
return {
data,
eventId,
setArgs,
remove : () => {
if (!eventId) return;
listeners.delete(eventId);
if (listeners.size === 0) {
eventSource.close();
}
},
}
}
This new option looks useful. I have the same issue — I also need to create the instance and open the connection only when needed.