Part 2 - Complete React.js Progressive Master Question Bank
50 progressive React.js interview questions covering JSX compilation, Virtual DOM & Fiber architecture, Hooks internals, state management, SSR/RSC, and performance profiling.
Q1: What is the Virtual DOM and how does Reconciliation work in React?
The Virtual DOM (VDOM) is an in-memory lightweight JS object representation of the real DOM. When state or props change, React creates a new Virtual DOM tree and runs a diffing algorithm during Reconciliation to calculate the minimal set of real DOM operations required.
// What JSX converts into (Virtual DOM Node object)
const vdomNode = {
type: 'button',
props: {
className: 'btn-primary',
onClick: () => console.log('Clicked'),
children: 'Submit'
}
};- Virtual DOM minimizes direct real DOM manipulations to boost rendering performance.
- React uses a heuristics O(n) diffing algorithm during Reconciliation to compute minimal real DOM updates.
What is the primary benefit of React's Virtual DOM Reconciliation process?
Q2: What is React Fiber and how does it improve application responsiveness?
React Fiber is the re-implementation of React's core reconciliation algorithm introduced in React 16. It breaks rendering work into incremental units of work called Fiber nodes, enabling React to pause, resume, assign priority to, or abandon work as higher-priority user inputs arrive.
// Fiber tree structure snippet (Internal React Node Representation)
const fiberNode = {
type: 'div',
child: childFiberNode,
sibling: siblingFiberNode,
return: parentFiberNode,
pendingProps: nextProps,
lanes: PriorityLanes // Tracks execution priority
};- Replaces synchronous stack reconciliation with asynchronous cooperative scheduling.
- Enables time-slicing and priority-based scheduling for smooth 60fps user interactions.
Which phase of Fiber execution is interruptible by higher-priority tasks?
Q3: How is JSX compiled under the hood in modern React?
JSX is a syntax extension for JavaScript. It does not run natively in browsers. Compilers like Babel transform JSX tags into React.createElement() calls (or _jsxRuntime.jsx() in React 17+ JSX transform) that return plain Virtual DOM objects.
// 1. Input JSX
const element = <h1 className="title">Hello World</h1>;
// 2. Output (Compiled JS via Babel React 17+ Runtime)
import { jsx as _jsx } from 'react/jsx-runtime';
const element = _jsx('h1', { className: 'title', children: 'Hello World' });- JSX is syntactic sugar for
React.createElement()or_jsx()calls. - Modern JSX transform eliminates the need to explicitly import
Reactin every file.
What does a JSX tag <MyComponent /> evaluate to after compilation?
Q4: What is the fundamental difference between State and Props?
Props (short for properties) are read-only input parameters passed down from a parent component to a child component. State is internal data managed locally within a component that can change over time in response to user actions or network events, triggering re-renders.
function CounterContainer() {
const [count, setCount] = useState(0); // Local State
return <CounterDisplay value={count} onIncrement={() => setCount(count + 1)} />; // Passed as Props
}
function CounterDisplay({ value, onIncrement }) {
return <button onClick={onIncrement}>Count: {value}</button>;
}- Props flow unidirectionally downward and are immutable by the child component.
- State is local, mutable via state updater functions, and triggers re-renders on update.
What happens if a child component attempts to reassign props.title = 'New Title' directly?
Q5: Why are 'keys' required when rendering lists in React, and why avoid index keys?
Keys give items in a list a stable identity. React uses keys during the reconciliation diffing process to identify which items were added, updated, or removed. Using array indices as keys can lead to subtle rendering bugs, input state corruption, and sub-optimal reconciliation if list items are reordered or filtered.
function TodoList({ todos }) {
return (
<ul>
{todos.map(todo => (
// RECOMMENDED: Unique item ID key
<li key={todo.id}>{todo.text}</li>
))}
</ul>
);
}- Keys allow React to match Virtual DOM list nodes across re-renders efficiently.
- Avoid array indices as keys when items can be reordered, inserted, or removed.
What issue occurs when using array indices as keys for a dynamic reorderable list?
Q6: How does useState work internally and why is state batching used?
useState stores state variables inside the component Fiber node's linked list of hooks. Calling a state setter function enqueues a update action on the Fiber queue. React batches multiple state updates within event handlers into a single re-render cycle to optimize performance.
function Counter() {
const [count, setCount] = useState(0);
const handleMultipleIncrements = () => {
// Functional updates queue operations on Fiber state queue
setCount(prev => prev + 1);
setCount(prev => prev + 1);
// React batches these calls into a single component re-render pass
};
return <button onClick={handleMultipleIncrements}>Count: {count}</button>;
}- Hook states are preserved inside a linked list attached to the component Fiber instance.
- Automatic batching (React 18) combines multiple state updates into single re-render updates.
Why should you pass a callback function to setState (setCount(prev => prev + 1)) when new state depends on previous state?
Q7: How does useEffect manage side-effects, dependencies, and cleanup cycles?
useEffect executes side-effects after the component renders and DOM updates are committed. The dependency array controls when the effect executes: omitting it runs after every render, an empty array [] runs once on mount, and passing dependencies [a, b] runs when specified variables change. Returning a function triggers cleanup before re-executing or unmounting.
useEffect(() => {
const subscription = api.subscribeToData(id);
// Cleanup closure function
return () => {
subscription.unsubscribe();
};
}, [id]); // Re-subscribes if 'id' changes- Runs asynchronously after paint to prevent blocking browser rendering.
- Cleanup function executes prior to effect re-execution and component unmounting.
When does the cleanup function returned inside useEffect execute?
Q8: What are the Rules of Hooks and why are they enforced?
- Only call Hooks at the Top Level: Don't call Hooks inside loops, conditions, or nested functions.
- Only call Hooks from React Functions: Call Hooks from Functional Components or Custom Hooks. Enforced because React relies on the exact execution order of Hooks across re-renders to map state variables to internal Fiber linked list nodes.
// ❌ BAD: Conditional Hook call alters Hook execution order
if (isLoggedIn) {
useEffect(() => fetchUserData(), []);
}
// ✅ GOOD: Keep Hook top-level, move condition inside Hook
useEffect(() => {
if (isLoggedIn) {
fetchUserData();
}
}, [isLoggedIn]);- React tracks Hook states using an ordered linked list on the Fiber node.
- Conditional Hook calls alter execution order, mismatching state bindings.
Why does calling a Hook inside an IF statement break React applications?
Q9: What is the difference between useMemo and useCallback?
useMemo: Caches the result value of an expensive calculation (useMemo(() => computeValue(a), [a])).useCallback: Caches the function instance itself between re-renders (useCallback(() => handleClick(), [])) to prevent breaking child componentReact.memoreference equality checks.
// Memoize calculated result value
const expensiveValue = useMemo(() => {
return calculateBigData(data);
}, [data]);
// Memoize callback function reference pointer
const handleAction = useCallback(() => {
console.log('Action performed for id:', id);
}, [id]);useMemomemoizes computed return values.useCallbackmemoizes function reference pointers across renders.
What primary performance issue does useCallback solve when passing functions to memoized child components?
Q10: What is useRef and how does it differ from useState?
useRef returns a mutable object { current: initialValue } whose reference persists across re-renders. Modifying ref.current does not trigger a component re-render. It is used to access direct DOM nodes or store instance variables that shouldn't cause UI updates when mutated.
function TextInputWithFocus() {
const inputEl = useRef(null);
const onButtonClick = () => {
// Imperative focus targeting
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus Input</button>
</>
);
}- Mutating
.currentupdates values synchronously without causing a re-render. - Commonly used for imperative DOM access (focus, canvas, media playback) and timer IDs.
What happens to the UI component when you assign timerRef.current = setTimeout(...) inside a click handler?