Skip to main content

Streams

For endpoints made with getSSE.

function Activity() {
type Event = StreamEvent<typeof client.activity.get>;
const [events, setEvents] = useState<Event[]>([]);

const feed = useStream(client.activity.get, {}, (event) => {
setEvents((previous) => [event, ...previous].slice(0, 6));
// Someone changed notes, possibly in another tab: refetch what's on screen.
store.refresh(refreshes.notes);
});

return (
<section aria-label="Activity">
<h2>Activity</h2>
{feed.error ? (
<p className="error">
Live updates stopped.{" "}
<button type="button" onClick={feed.reconnect}>
Reconnect
</button>
</p>
) : (
!feed.isStreaming && <p className="muted">Live updates ended.</p>
)}
{events.length === 0 ? (
<p className="muted">Changes to notes show up here as they happen.</p>
) : (
<ul>
{events.map((event) => (
<li key={event.id}>
{event.by} {event.action} “{event.note}”
</li>
))}
</ul>
)}
</section>
);
}

In this example:

  • The callback runs for every event. Events are not stored: you decide what to keep, and what to refresh.
  • store.refresh(...) refetches what's on screen when someone else changed it.
  • The connection is closed when the component unmounts, and opened again when the arguments change.
  • A rejected connection (e.g. 401) throws to the nearest <Boundary>, like a failed read.
  • A network failure is kept as error, with isStreaming: false: streams drop, and the page should stay. reconnect() tries again.
  • StreamEvent gives you the event type from the server.