Interview
React Interview Questions
Master React interview prep, covering core concepts, hooks, rendering lifecycle, state management patterns, performance optimization, and scenario-based coding challenges.
1. Learning Objectives
In this interview preparation guide, you will master the most common technical questions asked during React interviews. By the end of this session, you will be able to:
- Explain React's reconciliation algorithm and the Virtual DOM diffing process.
- Differentiate between controlled and uncontrolled components with trade-off analysis.
- Describe the rules of hooks and why they cannot be called conditionally.
- Answer scenario-based questions on performance optimization, state lifting, and re-render prevention.
- Debug and resolve common production issues including stale closures, infinite loops, and key warnings.
2. Overview
React interviews test deep understanding of rendering mechanics, hook lifecycle, state management trade-offs, and performance optimization strategies. This guide covers the most frequently asked questions organized by difficulty tier.
3. Core Concept Questions
Q1: What is the Virtual DOM and how does React's reconciliation work?
View SolutionAnswer: The Virtual DOM is a lightweight JavaScript object tree that mirrors the actual DOM. When state changes:
- React creates a new Virtual DOM tree representing the updated UI.
- It diffs the new tree against the previous one using its reconciliation algorithm.
- It computes the minimum set of DOM mutations needed.
- It batches and applies only those mutations to the real DOM.
React uses two key heuristics: (1) elements of different types produce different trees, and (2) the key prop hints which children are stable across renders.
Q2: What is the difference between controlled and uncontrolled components?
View SolutionAnswer:
- Controlled components: Form input values are driven by React state. The component's
valueprop is set to state, and anonChangehandler updates the state. React is the single source of truth. - Uncontrolled components: Form input values are managed by the DOM itself. You access the value via a
ref(e.g.,inputRef.current.value). Useful for simple forms or integrating with non-React code.
Trade-off: Controlled components give you full control (validation, formatting, conditional disabling) but require more boilerplate. Uncontrolled components are simpler but offer less control.
Q3: What are the Rules of Hooks and why do they exist?
View SolutionAnswer: There are two rules:
- Only call hooks at the top level — never inside loops, conditions, or nested functions.
- Only call hooks from React functions — either function components or custom hooks.
Why: React relies on the order in which hooks are called to associate each hook with its internal state slot. If a hook is called conditionally, the order changes between renders, and React maps the wrong state to the wrong hook.
Q4: What is the difference between useEffect, useLayoutEffect, and useMemo?
Answer:
- useEffect: Runs asynchronously after the browser paints. Used for side effects like API calls, subscriptions, and DOM measurements that don't need to block painting.
- useLayoutEffect: Runs synchronously after DOM mutations but before the browser paints. Used for DOM measurements that must happen before the user sees the screen (e.g., measuring element dimensions for positioning).
- useMemo: Caches a computed value between renders. It runs during rendering, not after. It is not for side effects — it is for avoiding expensive recalculations.
Q5: Why does React require keys on list items, and what happens if you use array index as the key?
View SolutionAnswer: Keys help React identify which items in a list have changed, been added, or been removed during reconciliation. Without stable keys, React cannot efficiently reuse existing DOM nodes.
Using array index as the key is problematic when the list order changes (items are added, removed, or reordered). React associates component state with the key — if a key's position changes but the key stays the same (because it's just the index), React reuses the wrong component instance, causing stale state and visual bugs.
Best practice: Use a stable, unique identifier from your data (like a database ID) as the key.
4. Scenario-Based Questions
Q1: A component re-renders 50+ times per second when a parent's state changes. How do you diagnose and fix this?
View SolutionDiagnosis: Use React DevTools Profiler to identify which components are re-rendering and why. Common causes:
- Parent passes a new object/array/function reference on every render (e.g., inline
style={{...}}oronClick={() => ...}). - Context value changes cause all consumers to re-render.
Remediation:
- Wrap the child component in
React.memo()to skip re-renders when props haven't changed. - Stabilize callback references using
useCallback. - Memoize object/array props using
useMemo. - Split context into smaller, focused contexts so changes don't cascade to unrelated consumers.
Q2: Your useEffect creates an infinite loop, causing the browser tab to freeze. How do you debug and fix it?
Diagnosis: An infinite loop occurs when useEffect modifies a value that is also in its dependency array, causing the effect to re-trigger itself endlessly.
Common pattern:
Fix: Use the functional updater form of the setter, which doesn't require items in the dependency array:
Q3: You need to share state between two sibling components that don't have a direct parent-child relationship. What are your options?
View SolutionAnswer: There are several approaches, ordered by complexity:
- Lift state up: Move the shared state to the nearest common ancestor and pass it down as props.
- Context API: Create a context provider wrapping both components. This avoids prop drilling but causes all consumers to re-render on any context value change.
- External state library: Use Zustand, Redux Toolkit, or Jotai for complex shared state with fine-grained subscriptions.
Trade-off: Lifting state is simplest but can cause prop drilling. Context is convenient but can cause performance issues. External libraries add a dependency but provide the most control.
5. Code Challenges
Challenge 1: Fix this component that has a stale closure bug:
Diagnosis: The empty dependency array [] means the effect runs only once at mount. The count variable inside the closure is captured as 0 and never updates. Every interval tick sets count to 0 + 1 = 1.
Fix: Use the functional updater form, which always receives the latest state:
Challenge 2: Fix this component that re-renders every child on every keystroke:
Diagnosis: Every keystroke in the search input causes Parent to re-render. The inline onClick={() => alert(item)} creates a new function reference each render, defeating React.memo on ExpensiveChild.
Fix: Wrap ExpensiveChild in React.memo and stabilize the callback with useCallback:
Challenge 3: Explain why this custom hook leaks memory and fix it:
Diagnosis: The useEffect adds an event listener but never removes it. When the component unmounts, the listener persists, calling setSize on an unmounted component — causing memory leaks and "Can't perform a React state update on an unmounted component" warnings.
Fix: Return a cleanup function that removes the event listener:
6. Advanced Concept Questions
Q1: What is React Fiber and how does it improve rendering?
View SolutionAnswer: React Fiber is the internal reconciliation engine introduced in React 16. It replaces the older stack-based reconciler with an incremental rendering architecture that can:
- Pause and resume work: Break rendering into small units of work, yielding to the browser between chunks to maintain 60fps responsiveness.
- Assign priorities: User interactions (like typing) get higher priority than background updates (like data fetching).
- Abort outdated work: If a higher-priority update arrives, Fiber can abandon in-progress low-priority work and restart.
This enables features like Concurrent Mode, Suspense, and Transitions.
Q2: What is the difference between React.memo, useMemo, and useCallback?
Answer:
- React.memo: A higher-order component that wraps a component. It skips re-rendering if props haven't changed (shallow comparison). It memoizes the component output.
- useMemo: A hook that caches a computed value between renders. It recomputes only when its dependencies change.
- useCallback: A hook that caches a function reference between renders. It is equivalent to
useMemo(() => fn, deps). Used to prevent child re-renders when passing callbacks as props.
Summary: React.memo = memoize a component. useMemo = memoize a value. useCallback = memoize a function.
Q3: How does React's batching behavior work, and how did it change in React 18?
View SolutionAnswer: State batching combines multiple setState calls into a single re-render for performance.
- React 17 and earlier: Batching only worked inside React event handlers. State updates inside
setTimeout,fetch.then(), or native event listeners triggered separate re-renders for eachsetStatecall. - React 18 (Automatic Batching): All state updates are batched regardless of where they originate — inside timeouts, promises, native event handlers, or any other context. This reduces unnecessary re-renders automatically.
To opt out of batching in React 18, use flushSync() from react-dom.
7. Summary & Key Takeaways
- React uses a Virtual DOM with a diffing algorithm to minimize real DOM mutations.
- Hooks must always be called in the same order — never conditionally.
- Use the functional updater form (
setState(prev => ...)) to avoid stale closures in effects. - Use
React.memo,useMemo, anduseCallbackstrategically to prevent unnecessary re-renders. - Always return cleanup functions from
useEffectwhen adding event listeners or subscriptions. - React 18 automatically batches all state updates, not just those in event handlers.