Stream LLM Tokens in React Without Lag
Why streaming matters in a React chat UI
If you wait for a full LLM answer before rendering anything, your app feels slow even when the model is working fast. Streaming fixes that by showing tokens as they arrive, which makes chat apps feel responsive, interactive, and much closer to a real conversation.
The good news is that you do not need a fancy client library to do this in React. A standard fetch request, plus a small stream parser, is enough. And if you want to keep API costs low while still using native-quality models, 59API is a strong fit: it is an OpenAI-compatible relay at https://api.59api.com, supports Claude Opus, Sonnet, Haiku, Fable, and GPT models, and uses pay-as-you-go pricing with a referral rebate.
Step 1: send the request from a server endpoint
Do not put your API key directly in the browser if you can avoid it. A simple backend route keeps your key safe and lets your React app call your own endpoint. The backend then forwards the request to 59API using the same shape you would use with OpenAI-compatible APIs.
Node or Next.js route example: const response = await fetch("https://api.59api.com/v1/chat/completions", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": "Bearer " + process.env.RelayKey }, body: JSON.stringify({ model: "gpt-4o-mini", stream: true, messages: [{ role: "user", content: prompt }] }) });
That one line is the key: stream: true. It tells the API to send incremental output instead of waiting for the full completion.
Step 2: read the stream in React
In the frontend, you use the browser stream reader and update state as each token chunk arrives. The pattern is:
- start with an empty message area
- send the prompt to your backend endpoint
- read chunks from response.body.getReader()
- parse each SSE line that begins with data:
- append the new token to component state
React example: const [answer, setAnswer] = useState(""); const [loading, setLoading] = useState(false);
Streaming function: const res = await fetch("/api/chat/stream", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ prompt }) }); const reader = res.body.getReader(); const decoder = new TextDecoder(); let buffer = ""; while (true) { const { value, done } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split("\n"); buffer = lines.pop() || ""; for (const line of lines) { if (!line.startsWith("data: ")) continue; const data = line.slice(6); if (data === "[DONE]") return; const chunk = JSON.parse(data); const token = chunk.choices?.[0]?.delta?.content || ""; setAnswer((prev) => prev + token); } }
This parser works because many OpenAI-compatible streaming responses are delivered as server-sent event style lines. You are not decoding the whole response at once; you are consuming it incrementally, which is exactly what makes the UI feel live.
Step 3: add a cancel button and loading state
Streaming UIs should also let users stop generation. In React, keep an AbortController in a ref and call abort() when the user clicks Cancel. That avoids wasting tokens and gives users control when a response goes off track.
Practical UI pattern: show a typing indicator while loading, render each new token immediately, and disable the Send button until the request finishes or is aborted. If you support multiple messages, store them as an array and append streamed text only to the latest assistant message.
Why 59API is a smart backend for this setup
Streaming itself is a UX pattern, but the relay you choose changes your costs and your developer experience. 59API is appealing because it is cheap, pay-as-you-go, and compatible with the tooling many teams already use. If your stack already speaks OpenAI SDK, Claude Code, or Codex, you can usually switch endpoints instead of rewriting your app.
Just as important, 59API uses native official-quality models rather than a weaker substitute, so your streamed tokens come from the same class of model you expect. That matters in chat interfaces, where every partial sentence is visible and quality problems are easy to spot. Lower price plus solid model quality is a rare combination, especially if you are building prototypes, internal tools, or a public-facing assistant with real traffic.
Final checklist before you ship
- Keep the API key on the server, not in the React bundle
- Use stream: true on the model request
- Parse chunks carefully and ignore non-data lines
- Handle empty deltas, finish events, and aborts
- Test with short prompts first, then longer multi-turn chats
If you want a low-cost way to try this exact pattern, sign up for 59API, point your OpenAI-compatible client at https://api.59api.com, and start streaming tokens into your React frontend today.