Skip to content

Instantly share code, notes, and snippets.

@arekbartnik
Forked from Mosharush/README.MD
Created September 19, 2025 02:05
Show Gist options
  • Select an option

  • Save arekbartnik/f1115bba861ccf5114c9b01a7229cc1d to your computer and use it in GitHub Desktop.

Select an option

Save arekbartnik/f1115bba861ccf5114c9b01a7229cc1d to your computer and use it in GitHub Desktop.
React Hook - Server-Sent Events (SSE)

Server-Sent Events (SSE) are commonly used in real-time applications where the server needs to push updates to the client.

Here are a few use cases:

  1. Real-time notifications: SSE can be used to push notifications to the client in real-time. For example, in a social media application, the server can push notifications about new posts, likes, comments, etc.
  2. Live news updates: In a news application, the server can push live news updates to the client.
  3. Real-time analytics: In an analytics dashboard, the server can push real-time data updates to the client.
  4. Chat applications: In a chat application, the server can push new messages to the client in real-time.
  5. Online multiplayer games: In an online multiplayer game, the server can push game state updates to the client in real-time.
  6. Stock price updates: In a stock trading application, the server can push real-time stock price updates to the client.

useSse - Server-Sent Events Hook

useSse is a custom React hook for handling Server-Sent Events (SSE) in your application.

Usage

Here's a basic example of how to use the useSse hook:

import { useEffect } from 'react';
import useSse from './useSse';

const MyComponent = () => {
  const {
    connectionState,
    connectionError,
    addListener,
    getEventData,
    closeConnection,
  } = useSse('https://my-api.com/events', { withCredentials: true });

  // register the listener once, clean it up on unmount
  useEffect(() => {
    const remove = addListener('myEvent', data => {
      console.log('Received data:', data);
    });

    return () => {
      remove?.();          // detach the listener
      closeConnection();   // close the SSE connection
    };
  }, [addListener, closeConnection]);

  // grab the latest payload for this event on every render
  const data = getEventData('myEvent');

  return (
    <div>
      <p>Connection state: {connectionState}</p>
      {connectionError && <p>Error: {connectionError.message}</p>}
      {data && <p>Last payload: {data}</p>}
    </div>
  );
};

export default MyComponent;

API

The useSse hook returns an object with these properties:

  • connectionState: current state of the SSE connection (CONNECTING, OPEN, CLOSED)
  • connectionError: an Event object describing the most recent connection error, or null if none occurred
  • addListener(eventName, handler): registers a listener for the specified event; the handler receives the event data string. The function returns a cleanup callback you can call (or return from a useEffect) to remove the listener when needed
  • getEventData(eventName): returns the latest payload string for the given event name. Because it comes from React state, a component that reads this value will automatically re-render whenever the payload changes
  • closeConnection(): closes the underlying EventSource and updates connectionState to CLOSED
const express = require('express');
const SSE = require('sse-stream');
const app = express();
const sse = SSE();
app.get('/events', sse, (req, res) => {
setInterval(() => {
const data = Math.random().toString(); // Generate random data
res.sse.event('MyEvent', data);
}, 1000);
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
import { useEffect, useState, useCallback } from 'react';
interface EventData {
[key: string]: string;
}
const useSse = (url: string, options?: EventSourceInit) => {
const [connectionState, setConnectionState] = useState('CONNECTING');
const [connectionError, setConnectionError] = useState<Event | null>(null);
const [eventSource, setEventSource] = useState<EventSource | null>(null);
const [eventData, setEventData] = useState<EventData>({});
// open the connection once and tidy up on unmount or when url / options change
useEffect(() => {
const es = new EventSource(url, options);
setEventSource(es);
es.onopen = () => setConnectionState('OPEN');
es.onerror = (err: Event) => {
setConnectionState('CLOSED');
setConnectionError(err);
};
return () => es.close();
}, [url, options]);
// register a listener for a specific event name
const addListener = useCallback(
(eventName: string, handler: (data: string) => void) => {
if (!eventSource) return;
const listener = (evt: MessageEvent) => {
setEventData(prev => ({
...prev,
[eventName]: evt.data,
}));
handler(evt.data);
};
eventSource.addEventListener(eventName, listener);
return () => eventSource.removeEventListener(eventName, listener);
},
[eventSource],
);
// simple getter: no hooks inside so rules of hooks are respected
const getEventData = useCallback(
(eventName: string) => eventData[eventName],
[eventData],
);
const closeConnection = useCallback(() => eventSource?.close(), [eventSource]);
return {
connectionState,
connectionError,
addListener,
getEventData,
closeConnection,
};
};
export default useSse;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment