React Interview Questions — Hard
Deep runtime internals, memory models, distributed design, concurrency failure modes, and architectural decisions.
Q1Deep-dive into React Fiber Architecture. What is it, why was it created, and how does cooperative scheduling work?
Answer: React Fiber is the complete rewriting of React's core reconciliation algorithm, released in React 16.
Why it was created: Before Fiber (the "Stack Reconciler"), React navigated the virtual DOM tree recursively. Once a render cycle started, it executed synchronously on the browser's main thread and could not be paused, aborted, or split. If the component tree was very large, a render cycle could take more than 16ms (the budget for 60fps), causing dropped frames, laggy input fields, and stuttering animations (commonly called "jank").
The Fiber Concept:
A "Fiber" is a plain JavaScript object that represents a unit of work. It maps to a React element and a DOM node, but unlike elements, fibers are long-lived and mutable. They contain metadata about state, props, output, and references to other fibers (child, sibling, and return).
Cooperative Scheduling & Work Splitting:
Fiber transforms the execution model from a call stack to a linked list traversal. This allows React to divide the rendering work into small chunks and yield execution back to the browser's main thread when necessary (cooperative scheduling), utilizing browser APIs like requestIdleCallback or React's custom scheduler.
The Two-Phase Lifecycle:
- Render Phase (Asynchronous, Interruptible):
- React traverses the fiber tree (linked list) to compute changes (diffing).
- It builds a "work-in-progress" tree.
- This phase is non-blocking and can be paused, discarded, or restarted if higher-priority work (like user keyboard inputs) enters the scheduler.
- No physical side effects (DOM mutations) occur in this phase.
- Commit Phase (Synchronous, Uninterruptible):
- React takes the completed work-in-progress tree (the "effects list") and applies changes to the actual DOM.
- This phase must execute synchronously in a single pass to prevent user-facing UI inconsistencies (flickering).
- Lifecycle methods like
componentDidMount,componentDidUpdate, and effects likeuseLayoutEffectanduseEffectare scheduled or fired here.
Q2Explain React 18 Concurrent Features, Priority Lanes, and "Tearing".
Answer: Concurrent Rendering is not a feature in itself but an underlying capability of React 18 that enables the UI to be interruptible.
1. Priority Lanes: React internally uses a 32-bit bitmask system called Lanes to assign priorities to different types of updates:
SyncLane: For immediate interactive inputs (e.g., text inputs, clicking buttons).TransitionLane: For transitions that can afford to wait (e.g., filtering a large list, switching tabs).DefaultLane: For standard state updates.OffscreenLane: For background rendering.
2. Transitions (useTransition and useDeferredValue):
useTransition: Returns anisPendingboolean and astartTransitionfunction. Wrapping a state-setting callback instartTransitiontells React to treat that update as low priority (TransitionLane). If a user starts typing while a transition-driven render is in progress, React halts the transition render, processes the keystroke, and then restarts the transition render in the background.useDeferredValue: Takes a state value and returns a deferred copy of it. It delays rendering the deferred value until the main thread is idle, which is useful when customizing performance with third-party libraries where you cannot directly wrap state updates inuseTransition.
3. "Tearing" & useSyncExternalStore:
- Tearing occurs when a visual discrepancy is displayed on-screen because different parts of the UI render with different versions of the same state during a single repaint.
- Tearing became a serious risk with Concurrent Rendering when reading from external stores (like Redux, Zustand, or global browser APIs like
window.innerWidth). Because concurrent renders can pause and yield back to the main thread, an external event could modify the external store mid-render, causing components rendered later in the tree to read the new value while early-rendered components read the old value. - To solve this, React 18 introduced
useSyncExternalStore, which guarantees synchronous consistency by forcing updates to fall back to a synchronous, non-interruptible render if an external store update occurs during a concurrent render cycle.
Q3Explain how the React 18 Hydration process works, what "Selective Hydration" is, and what causes "Hydration Mismatch" errors.
Answer: Hydration is the process where client-side React takes over static HTML elements rendered on the server, attaches event listeners, and sets up state/effects, transforming it into a fully interactive single-page application.
Selective Hydration (React 18):
In older React versions, hydration was "all-or-nothing". The entire page's JS code had to load, and then the entire page had to hydrate before any element became interactive.
In React 18, wrapping slow-loading components in <Suspense> allows React to stream HTML from the server and perform Selective Hydration:
- It hydrates components that have loaded code without waiting for the rest of the page.
- If a user clicks a button in a non-hydrated component, React recognizes the click as high priority, pauses ongoing hydration elsewhere, and prioritizes hydrating that exact clicked component first (event-driven hydration).
Hydration Mismatches: A hydration mismatch occurs when the server-rendered HTML tree is structure-wise or content-wise different from what the client's React engine produces on its initial render.
- Common Causes:
- Using browser-only variables (e.g.,
window,localStorage, ordocument) during the initial render phase. - Outputting non-deterministic data like dates (
new Date()) or random numbers (Math.random()) on initial render without synchronization. - Invalid HTML markup structure (e.g., nesting a
<div>inside a<p>), which causes the browser to automatically correct the DOM structure, creating a mismatch with React's expectation.
- Using browser-only variables (e.g.,
- How to fix:
- Use
useEffectto trigger client-only rendering changes after mounting. - For intentional differences, use the
suppressHydrationWarningprop on the matching HTML element (use sparingly!).
- Use
Q4Deep-dive into State Scheduling under the hood. How does React manage the state update queue?
Answer:
When a state update is triggered (e.g., calling setCount), React does not calculate the next state immediately. Instead, it creates an Update Object containing:
- The next value or update function (e.g.,
prev => prev + 1). - The update's priority Lane.
- A reference link to the next update object (forming a circular linked list queue).
Under the hood steps:
- Queueing: React appends the update object to the Fiber's
updateQueue. - Scheduling: React schedules a work cycle for the root of the fiber tree with the priority matching the lanes of the update queue.
- Execution (Render Phase):
- When the scheduler executes this fiber, React traverses the
updateQueue. - It skips updates whose lanes are lower-priority than the current render's active Lane.
- It computes the cumulative state by sequentially applying all high-priority updates.
- Critical Optimization (Interleaved Updates): If a skipped update was in the middle of the queue, React remembers the state before that update, so that in the next low-priority render cycle, it can re-apply all updates in the correct chronological order, ensuring state remains accurate.
- When the scheduler executes this fiber, React traverses the
- Re-conciliation & DOM Commit: The final state is compared to the current DOM, and necessary changes are applied in the Commit Phase.
Q5Walk through Fiber's beginWork/completeWork phases and effect-list construction.
- beginWork (downward pass): for each fiber React checks bailout conditions (props unchanged + no forced update/context dirt) — bailing returns the cached alternate subtree instantly. Otherwise it invokes the component function, reconciles returned elements against current children (
reconcileChildFibers), tagging work: Placement/Update/Deletion, and clones fibers into the workInProgress tree preservingalternatelinks. - completeWork (upward pass): finalizes host fibers — diffs old/new props into an update payload queue, computes
childLanes/subtreeFlagsbitmask rollups so ancestors know whether subtrees contain pending work (enables early exits), and stitches firstEffect/nextEffect linked lists collecting mutation/layout effects instead of traversing again later. - Deletions attach to
deletionsarray processed in commit; text/host updates bundle into minimal DOM ops. - Interview depth signal: explain how subtreeFlags lets the commit phase skip entire clean subtrees, and how alternates get reused (double buffering) across renders.
Unlock the remaining 48 React (Hard) questions
You've completed the 5 free sample questions. Get unrestricted lifetime access to every question, model answer, implementation challenge, and all 27+ technologies for a single payment.
₹399 India / $9 International · One-time settlement · Zero subscription