Concurrent Rendering
Slap yourself if
You think concurrent rendering means React renders in parallel threads or it always makes apps faster.
Why this exists
Concurrent rendering exists to keep the UI responsive under heavy work by allowing React to pause, resume, and abandon rendering work, prioritizing urgent updates (like typing) over non-urgent work (like rendering a big list).
Mental model
Concurrent rendering makes rendering interruptible. React can start rendering an update, pause it to handle something more urgent, then resume later. The key idea is that rendering work can be done in pieces and may never be committed if a newer update supersedes it.
- An update is scheduled (e.g., state change).
- React starts rendering a new UI tree in memory (work-in-progress).
- If higher-priority work arrives, React can pause the current render and switch to the urgent update.
- React may resume the paused work later, or throw it away if it becomes obsolete.
- Only when React commits does it apply changes to the DOM; rendering work before commit is not visible to the user.
- Assuming render is a single uninterrupted pass; code that relies on timing breaks.
- Race conditions in UI state when multiple async updates interleave.
- Reading mutable external state during render leading to inconsistent UI (tearing).
- Memoization bugs: relying on referential equality while mutating data.
- Stale closure issues becoming more visible when updates are interrupted and resumed.
Concurrent rendering is React’s ability to interrupt and resume rendering work so urgent updates can stay responsive. React can prepare multiple versions of the UI in memory and only commit the latest one, abandoning intermediate work if needed.
- Concurrent rendering means React uses multiple threads to render.
- Concurrent rendering always improves performance.
- If a component rendered, it must have updated the DOM.
Deep dive
Premium deep dives include more internals, more scars.
Work-in-progress trees, interruptibility, and commit
- Render phase vs commit phase
- Work-in-progress (WIP) vs current tree
- Why DOM updates only happen at commit
Tearing, races, and priority inversion in UI
The hardest bugs are consistency bugs: the UI can momentarily reflect mixed versions of state if you read external mutable sources incorrectly.
How innocent code becomes a concurrency bug
- Mutating objects breaks memoization assumptions
- Stale closures become visible under interruption
Tradeoffs: responsiveness vs predictability
Concurrency trades a simpler mental model for better responsiveness under load.
Performance impact and when it helps
Concurrency helps most when the main thread is busy and you need to protect interaction latency.
Related terms
Time Slicing
You think time slicing is just 'splitting work' or the same thing as code splitting.
Scheduler priorities
You think priorities are just performance hints and not correctness boundaries.
Fiber Architecture
You think Fiber is just a rewrite of the Virtual DOM or that it exists only to make React faster.
Reconciliation Algorithm
You think reconciliation is just 'diffing the Virtual DOM' or that React compares trees node-by-node exhaustively.
Stale Closure Problem
You think closures automatically update when state changes or that stale closures are just a React Hooks quirk.
Tearing in concurrent UI
You assume a render either fully happens or doesn’t happen at all.
Suspense boundaries
You think Suspense is just a loading spinner with better ergonomics.