Skip to main content

React Integration

Add real-time WebSocket features to your React app using the @sukko/react package.

Time to complete

~10 minutes

Prerequisites​

  • A running Sukko instance (Quickstart)
  • A React 18+ application
  • A backend endpoint that generates Sukko JWT tokens

Install​

npm install @sukko/sdk @sukko/websocket @sukko/react

Setup Provider​

Wrap your app with SukkoProvider. Pass options (a SukkoClientOptions) to have the provider create and own the client, or pass a pre-built client:

// src/App.tsx
import { SukkoProvider } from '@sukko/react';
import { WebSocketTransport } from '@sukko/websocket';

function App() {
return (
<SukkoProvider
options={{
transport: new WebSocketTransport({ url: 'ws://localhost:3000' }),
getToken: async () => {
const res = await fetch('/api/auth/sukko-token');
return res.text();
},
}}
>
<ChatRoom />
</SukkoProvider>
);
}

The provider connects on mount and disconnects on unmount (for clients it created). getToken is called on connect and before token expiry — your backend should return a fresh JWT.

Subscribe to a Channel​

useSubscription takes an array of channels. It returns the most recent message (lastMessage / data), plus an onMessage callback for streaming — accumulate a list yourself when you need history:

import { useState } from 'react';
import { useSubscription, type TypedMessage } from '@sukko/react';

function ChatRoom() {
const [messages, setMessages] = useState<TypedMessage[]>([]);

useSubscription({
channels: ['general.chat'],
onMessage: (msg) => setMessages((prev) => [...prev, msg]),
});

return (
<ul>
{messages.map((msg, i) => (
<li key={i}>{JSON.stringify(msg.data)}</li>
))}
</ul>
);
}

For a single latest-value view (e.g. a live price), read data directly:

const { data } = useSubscription<Trade>({ channels: ['tenant.BTC.trade'] });

Connection State​

import { useConnectionState } from '@sukko/react';

function StatusBar() {
const { state, isConnected, isReconnecting } = useConnectionState();
// state: 'connecting' | 'connected' | 'reconnecting' | 'disconnected' | 'error'

return <span>Status: {state}</span>;
}

Publish a Message​

import { useSukkoClient } from '@sukko/react';

function MessageInput() {
const client = useSukkoClient();

const send = () => {
client.publish('general.chat', { text: 'Hello from React!' });
};

return <button onClick={send}>Send</button>;
}

Automatic Recovery​

There is no manual replay call. When the connection drops and reconnects, the SDK automatically replays messages missed during the gap (Kafka backend), tracking an opaque per-channel cursor. Where recovery can't be guaranteed it surfaces a gap / possible_gap marker on the client's messages() stream rather than dropping silently, and a truncated recovery fires a recoveryInterrupted event — subscribe to it with useSukkoEvent:

import { useSukkoEvent } from '@sukko/react';

function RecoveryWatcher() {
useSukkoEvent('recoveryInterrupted', (err) => {
console.warn('recovery interrupted:', err.message);
});
return null;
}

See the Vanilla TypeScript guide for the full recovery model and the messages() stream.

Complete Example​

import { useState } from 'react';
import { SukkoProvider, useSubscription, useSukkoClient, useConnectionState, type TypedMessage } from '@sukko/react';
import { WebSocketTransport } from '@sukko/websocket';

function ChatRoom() {
const [messages, setMessages] = useState<TypedMessage[]>([]);
const client = useSukkoClient();
const { state } = useConnectionState();

useSubscription({
channels: ['general.chat'],
onMessage: (msg) => setMessages((prev) => [...prev, msg]),
});

return (
<div>
<p>Connection: {state}</p>
<ul>
{messages.map((msg, i) => (
<li key={i}>{JSON.stringify(msg.data)}</li>
))}
</ul>
<button onClick={() => client.publish('general.chat', { text: 'Hello!' })}>
Send
</button>
</div>
);
}

export default function App() {
return (
<SukkoProvider
options={{
transport: new WebSocketTransport({ url: 'ws://localhost:3000' }),
getToken: () => fetch('/api/token').then((r) => r.text()),
}}
>
<ChatRoom />
</SukkoProvider>
);
}

Next Steps​