One-line React integration
fetchStream(url).live(setSnap) — the callback receives a fresh { data, chunks, done } wrapper, so React re-renders naturally. rAF throttling is the default in browsers.
Your UI sees data the moment the first bytes arrive — no waiting for the full response body like fetch().json() or axios.get() force you to.
fetch() and axios.get() both do the same thing: wait for the entire response body to arrive, then hand it to you as one blob. For a 3 MB JSON list on a slow network, that's a 3-second blank screen before your UI sees a single row.
// fetch — waits for full body, then JSON.parse, then render.
const res = await fetch("/api/users");
const users = await res.json(); // ⏳ 3 s on a 3 MB payload
render(users);// axios — same story.
const { data } = await axios.get("/api/users"); // ⏳ 3 s on a 3 MB payload
render(data);fetchstream-js reads the response as it streams in and hands you values as soon as their closing } arrives. Same URL, same server, same bytes — but your first row paints in milliseconds.
import { fetchStream } from "fetchstream-js";
await fetchStream("/api/users").live(({ data }) => render(data));
// rAF throttling is the default in browsers; one render per animation frame.That's it — .live() hands you { data, chunks, done, path } each tick. data is the same in-place-mutating tree (zero-copy reads); the wrapper itself is fresh, so React's setState re-renders without spread or counters.
import { fetchStream } from "fetchstream-js";
import { useEffect, useState } from "react";
export function Users() {
const [snap, setSnap] = useState({ data: null, chunks: 0, done: false });
useEffect(() => {
const ac = new AbortController();
fetchStream("/api/users", { signal: ac.signal }).live(setSnap);
return () => ac.abort();
}, []);
return <pre>{JSON.stringify(snap.data, null, 2)}</pre>;
}No reducers, no refs, no manual requestAnimationFrame. The library already throttles for you.
| Approach | Time to first row | Time to last row |
|---|---|---|
fetch().then(r => r.json()) | ~3 100 ms | ~3 100 ms |
axios.get(url) | ~3 100 ms | ~3 100 ms |
fetchStream(url).live(setState) | ~120 ms | ~3 100 ms |
Both finish at the same speed — the network hasn't changed. But your user sees rows 25× sooner, which is the metric that actually matters for perceived performance.
👉 See the full React benchmark demo
.live() hook pattern, ready to paste.live() coalesces updates