Quick-start: Python + React
Stream structured JSON from a FastAPI backend to a React client in under 10 minutes.
Install both packages
pip install jsoncurrent
npm install jsoncurrentSet up the FastAPI Emitter
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from jsoncurrent import Emitter
import anthropic
import asyncio
app = FastAPI()
client = anthropic.Anthropic()
@app.get('/stream')
async def stream():
queue = asyncio.Queue()
emitter = Emitter()
emitter.on('patch', lambda chunk: queue.put_nowait(f"data: {chunk.to_json()}\n\n"))
emitter.on('complete', lambda: queue.put_nowait("data: [DONE]\n\n"))
async def generate():
with client.messages.stream(
model="claude-opus-4-6",
max_tokens=4096,
messages=[{"role": "user", "content": "Generate a report as JSON..."}],
) as stream:
for text in stream.text_stream:
emitter.write(text)
emitter.flush()
while not queue.empty():
yield await queue.get()
return StreamingResponse(generate(), media_type="text/event-stream")Wire the React Collector
import { useJsonCurrent } from 'jsoncurrent/react'
import { useEffect } from 'react'
interface Report {
title: string
sections: { heading: string; body: string }[]
}
export function ReportViewer() {
const { data, status, consume, complete, reset } = useJsonCurrent<Report>()
useEffect(() => {
reset()
const source = new EventSource('/stream')
source.onmessage = (event) => {
if (event.data === '[DONE]') { complete(); source.close(); return }
consume(JSON.parse(event.data))
}
return () => source.close()
}, [])
return (
<div>
<h1>{data.title}</h1>
{data.sections?.map((section, i) => (
<section key={i}>
<h2>{section.heading}</h2>
<p>{section.body}</p>
</section>
))}
{status === 'streaming' && <p>Generating…</p>}
</div>
)
}Run it
# Terminal 1
uvicorn main:app --reload
# Terminal 2
npm run devconsume() expects a StreamingChunk object — deserialise from your transport with
JSON.parse() before calling it.
Next steps
Last updated on