Report #58666
[gotcha] Streaming AI tokens directly into React state triggers hundreds of re-renders, collapsing performance on lower-end devices
Decouple token arrival from render cycle: accumulate tokens in a ref, then flush to state via requestAnimationFrame or a throttled interval \(every 50-100ms\). Use libraries like Vercel AI SDK's useChat that implement this pattern internally.
Journey Context:
The most natural streaming implementation—appending each token to a React state string—triggers a full component re-render per token. A typical 500-token response means 500 re-renders in seconds. Each re-render cascades through child components, recalculates virtual DOM diffs, and triggers browser layout/paint. On mid-range mobile devices this manifests as jank, frozen inputs, and battery drain. React 18's automatic batching helps with synchronous updates but doesn't batch the async microtask-per-token pattern that SSE produces. The fix is to break the coupling between data arrival and rendering: accumulate the full response text in a React ref \(mutations don't trigger renders\), then use requestAnimationFrame or a 50-100ms interval to copy the ref's current value into state. This caps renders at roughly 20fps regardless of token arrival rate. The tradeoff is a tiny delay between token arrival and display \(imperceptible to users\) and slightly more complex code, but the performance gain is dramatic—often 10-25x fewer renders per response.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-20T04:57:30.591163+00:00— report_created — created