In the previous parts, we saw how Fiber (React 16) broke the rendering work into small chunks. It gave React the ability to pause, but the engine was still "Sequential." It worked on one task at a time, just with better interruptions.
React 18 changes the fundamental nature of time in React. It moves us from a "Sequential" world to a "Concurrent" one.
1. The React 16 Foundation: Fiber Root & Pausable Work
In React 16, we introduced the Fiber architecture. This gave us the "Work-in-Progress" tree and "Current" tree.
- The Mechanism: React could pause the "Render" phase to let the browser paint a frame, then resume.
- The Limit: Updates were prioritized using a simple countdown called Expiration Times. It was a linear queue where one update had to "win" over another.
2. The React 18 Solution: Concurrency & the "Lanes" Model
React 18 replaces "Expiration Times" with a Lanes Model.
How the Lanes Model Works:
Instead of a single timestamp for when an update expires, React now performs bitmask operations to group and filter work. Each "lane" represents a category of priority using a 32-bit integer.
-
Bitwise Priority: React assigns a specific bit to each type of task. For example:
-
Sync Lane:
0b0000000000000000000000000000001(Immediate updates like typing). - InputContinuous Lane: Used for things like scrolling or zooming.
- Default/Transition Lane: For data fetching or heavy list rendering.
-
Sync Lane:
Multitasking & Interleaving: Because these are bits, React can combine multiple lanes into a single "bundle" of work (e.g., handling three different transitions at once). If React is working on a "Transition Lane" and a user types in a search box, a "Sync Lane" bit is flipped. React sees this bit has a higher mathematical priority, pauses the transition work immediately, handles the keystroke, and then returns to the transition work.
The Highway Analogy: Think of the Lanes Model as a 32-lane highway. Different types of updates travel in their own dedicated lanes. Urgent updates (like typing) get priority lanes and can quickly "bypass" slower traffic (like background data fetching) in adjacent lanes.
Entanglement: If two updates depend on each other, React can "entangle" their lanes, forcing them to finish together so the UI doesn't look inconsistent.
3. Key Features Enabled by Concurrency
Automatic Batching
Previously, React only batched updates inside event handlers. React 18 now batches everything—even inside fetch(), setTimeout(), or native events. This cuts down on unnecessary re-renders by grouping multiple state changes into one single render pass.
Transitions (useTransition)
This is the most "human" part of the update. You can now explicitly tell React: "This update is not urgent."
- While the transition is rendering in the background, the UI remains interactive.
- Benefit: No more "janky" inputs while a heavy list is filtering.
Selective Hydration: Smarter Server-Side Rendering
React 18 also fixed the "All-or-Nothing" problem of SSR.
- The Old Way: You had to download and hydrate the entire page before you could click a single button.
-
The New Way: Using
<Suspense>, React can now stream HTML and selectively hydrate components. - The Benefit: If a user clicks a component that hasn't hydrated yet, React will "jump the lane" and hydrate that specific component first.
4. Why it is Beneficial
- Decoupled Rendering: You can start a heavy render in the background without freezing the input field.
-
Predictive UI: React can "prepare" a screen in a hidden lane while the user is still looking at the old screen, switching only when the new one is ready (this is the core of
Suspense). - No More "Jank": By splitting work into these 32 lanes, React ensures that high-frequency events (like mouse moves) always have a free lane to bypass slow computations.
Comparison: Expiration Times vs. Lanes
| Feature | Expiration Times (React 16) | Lanes Model (React 18) |
|---|---|---|
| Logic Type | Linear / Queue-based | Bitwise / Category-based |
| Multitasking | Sequential: One update at a time | Concurrent: Multiple updates can overlap |
| Priority Handling | Based on "age" (how long it's waited) | Based on "type" (User Input vs. Background) |
| Interruption | Limited: Hard to resume partially done work | Advanced: Can pause, branch, and resume work |
| Relationship | Updates are independent | Updates can be "entangled" together |
Conclusion: Mastering the Dimension of Time
React 18 didn't just make the engine faster; it made it smart. By moving from a simple "pausable" queue to a 32-lane Concurrent system, React evolved from a basic UI library into a sophisticated scheduler.
By mastering Bitmasks and Lanes, you’ve moved beyond basic state management. You now understand how React manages the most precious resource in the browser: Main Thread Time.
However, even with a smart engine, we still spend hours manually tweaking performance with useMemo and useCallback. In the final part of this series, we’ll look at the React 19 Compiler—the evolution that turns React from a library you have to optimize into one that finally optimizes itself.
📚 Deep Dive References
If you want to see the original "blueprints" for Concurrent React, these are the essential reads:
- React 18 Official Release Post: The high-level overview of the Concurrency shift. React v18.0 Release
- The Lanes Model (Original PR): The actual bitwise logic that replaced Expiration Times. React PR #18796 - Initial Lanes Implementation
- New Suspense Architecture: Deep dive into Selective Hydration and Streaming SSR. React WG - Selective Hydration Deep Dive
- The Transition API: How to talk to the Lanes model directly from your code. react.dev - useTransition Reference
Top comments (0)