Time slicing and work interruption
Time slicing is the technique that allows React to break rendering work into small chunks and spread them across multiple frames, keeping the UI responsive.Time slicing is the foundation of React’s concurrent mode. Without it, long renders would block the main thread and make the UI feel frozen.
How time slicing works
Check deadline
After each unit of work, React checks if it has exceeded its time budget (typically 5ms).
Yield or continue
If the deadline is reached, React yields control to the browser. Otherwise, it continues with the next unit of work.
- Without time slicing
- With time slicing
In traditional React, a large render blocks the main thread until completion:
- User input feels sluggish
- Animations stutter
- The page appears frozen
- All updates are synchronous
Work interruption
When a higher-priority update arrives during a render, React can interrupt the current work and start processing the urgent update.Detect high-priority update
A user interaction (like a click or text input) triggers a high-priority state update.
Interrupt current render
React immediately stops the current low-priority render, even if it’s halfway through.
Work interruption is why the render phase must be pure and side-effect free. React may call render functions multiple times or discard renders that never commit.
Priority inversion prevention
React prevents priority inversion where low-priority work blocks high-priority work:- Lane entanglement
- Starvation prevention
- Batching
When a low-priority update reads state from a high-priority update, their lanes become entangled. This ensures they render together and prevents inconsistent UI states.
Suspense and lazy loading
Suspense allows components to “wait” for asynchronous operations while showing a fallback UI. It’s React’s declarative approach to loading states.Basic Suspense usage
Catch the Promise
The nearest Suspense boundary catches the thrown Promise and shows the fallback UI.
Suspense works by catching thrown Promises during render. This is why data fetching libraries for Suspense must throw Promises when data isn’t ready.
Code splitting with lazy
Thelazy function enables component-level code splitting:
- Without lazy
- With lazy
Nested Suspense boundaries
You can nest Suspense boundaries to show loading states at different granularities:Independent loading states
Each Suspense boundary manages loading state for its children independently.
Granular fallbacks
Show specific loading UI for each section rather than a single page-wide spinner.
Nested Suspense boundaries enable progressive loading patterns where fast content appears first, with slower content appearing incrementally.
useTransition and useDeferredValue
These hooks provide APIs for marking updates as non-urgent, keeping the UI responsive during expensive state changes.useTransition
useTransition allows you to mark state updates as transitions, which are lower-priority and can be interrupted.
- Urgent updates
- Transition updates
Updates outside
startTransition are synchronous and high-priority:- User input in form fields
- Focus changes
- Toggling UI elements
- Immediate visual feedback
Keep UI responsive
React keeps the current UI interactive while processing the transition in the background.
Interrupt if needed
If the user makes another change, React can interrupt the transition and start a new one.
Transitions solve the problem of “slow updates blocking fast updates.” The input field updates immediately while expensive filtering happens in the background.
useDeferredValue
useDeferredValue provides a deferred version of a value that lags behind the actual value during transitions.
- useTransition
- useDeferredValue
isPending flag.When to use transitions
Expensive renders
Use transitions when state updates trigger expensive renders that would otherwise make the UI feel frozen.
Navigation
Route changes often involve loading new components and data. Transitions keep the current page interactive during navigation.
Filtering/sorting
When filtering or sorting large lists, transitions allow the filter input to update immediately while results update in the background.
Transitions are most effective when the slow part is rendering, not data fetching. For slow data fetching, combine transitions with Suspense.
Automatic batching
React automatically batches multiple state updates that occur in the same event handler or async context into a single re-render.- Before React 18
- React 18+
Automatic batching improves performance by reducing unnecessary re-renders. If you need to opt-out, use
ReactDOM.flushSync() to force synchronous updates.