I built a live preview engine that updates as you type — with zero delay.
The trick? Don't use React for the preview pane.
React's reconciliation adds 16-50ms per update. For a live preview that should feel instant, that's noticeable lag.
The Architecture
Instead of re-rendering a React component on every keystroke, I used:
- Web Worker for markdown parsing (off main thread)
-
Direct DOM manipulation via
innerHTML(no reconciliation) - RequestAnimationFrame for visual updates (smooth, no jank)
// Web Worker receives markdown
self.onmessage = (e: MessageEvent<string>) => {
const html = parseMarkdown(e.data);
self.postMessage(html);
};
// Main thread updates DOM directly
worker.onmessage = (e: MessageEvent<string>) => {
requestAnimationFrame(() => {
previewEl.innerHTML = e.data;
});
};
The Results
| Approach | Update Latency | Jank |
|---|---|---|
| React re-render | 16-50ms | Sometimes |
| React + useMemo | 8-20ms | Rarely |
| Web Worker + innerHTML | 0-3ms | Never |
Why This Matters
For tools like code editors, documentation writers, and CMS interfaces, the preview should feel like it's "just there." Any perceptible delay breaks the flow state.
The lesson: not everything needs to be a React component. Sometimes the fastest code is the framework you don't use.
More architecture deep dives: Codcompass
Top comments (0)