Skip to content

fetchstream-jsA drop-in replacement for fetch & axios

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.

fetchstream-js

The problem

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.

js
// 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);
js
// axios — same story.
const { data } = await axios.get("/api/users"); //  ⏳ 3 s on a 3 MB payload
render(data);

The fix

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.

js
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.

React in 8 lines

tsx
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.

Benchmark — 5 MB JSON payload, real network

ApproachTime to first rowTime 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

Where to next?

Released under the MIT License.