WebSocket, WebTransport & NDJSON
Each demo runs the real tanstack-fetch/live client in your browser against a mock server. No backend is needed. Guide: WebSocket, WebTransport & streams.
WebSocket: api.ws
- Click Connect, and send a message right away. It's queued until the socket opens.
- Click Drop connection to simulate a network drop (close code 1006).
- Watch it reconnect:
getToken()runs again, so the URL gets a fresh token (demo-token-v2, …).
Live demo · WebSocket
useWs — auth + reconnect
Chat against a mock socket. Send before it opens (queued), then drop the connection: it reconnects and getToken() runs again, so the URL gets a fresh token.
status: disconnected
import { createFetch } from 'tanstack-fetch/live'
import { useWs } from 'tanstack-fetch/react'
const api = createFetch({ baseUrl, getToken })
const ChatRoom = ({ id }: { id: number }) => {
const { data, status, send, close } = useWs<ChatMessage, { id: number }>('/rooms/:id', {
client: api,
params: { id },
authIn: 'query', // browsers can't send WS headers
reconnect: { retries: 3, delayMs: 600 },
})
return (
<>
<p>{status} · {data?.text}</p>
<button onClick={() => send({ text: 'hi' })}>Send</button>
<button onClick={close}>Close</button>
</>
)
}WebTransport: api.transport
Game state arrives as HTTP/3 datagrams, about 16 per second. send() pushes input back on the same session.
Live demo · WebTransport
useWs({ transport: 'webtransport' })
Game state streams in as unreliable datagrams (newest value wins). Same API as api.ws: send input back with send().
status: disconnected
import { useWs } from 'tanstack-fetch/react'
const Game = () => {
const { data: state, status, send } = useWs<GameState, { id: number }, Input>('/game/:id', {
client: api,
params: { id: 1 },
authIn: 'query',
transport: 'webtransport', // HTTP/3 datagrams
})
return (
<Board dot={state} live={status === 'connected'}
onBoost={() => send({ boost: 1.5 })} />
)
}NDJSON stream: api.stream
An LLM-style answer streamed one JSON line at a time, from a POST with a body and an Authorization header. Stop aborts the request through signal.
Live demo · NDJSON
api.stream + streamedQuery
A POST with a body and an Authorization header, read line by line. EventSource cannot do either.
status: disconnected
import {
experimental_streamedQuery as streamedQuery,
useQuery,
} from '@tanstack/react-query'
const Answer = ({ prompt }: { prompt: string }) => {
const { data: tokens = [], fetchStatus, refetch } = useQuery({
queryKey: ['chat', prompt],
queryFn: streamedQuery({
streamFn: ({ signal }) =>
api.stream<Token>('/chat', { body: { prompt }, signal }),
}),
enabled: false,
})
return (
<>
<button onClick={() => refetch()}>Ask</button>
<p>{tokens.map((t) => t.text).join('')}</p>
{fetchStatus === 'fetching' && <span>streaming…</span>}
</>
)
}Framework hooks
useWs gives you the same socket as reactive state in React, Vue, Solid, Svelte and Angular:
import { useWs } from 'tanstack-fetch/react'
const { data, status, send } = useWs<ChatMessage, { id: string }>('/rooms/:id', {
client: api,
params: { id },
authIn: 'query',
// transport: 'webtransport',
})See the useWs section in each guide: React · Vue · Solid · Svelte · Angular.
