React interviews in 2026 are not "do you know the API." Senior interviewers assume you know the API — they use the React questions to test how deeply you understand rendering, state, and performance, and whether you can reason about trade-offs the way a principal engineer would.
The 35 questions below reflect real React interview loops across startups, mid-market companies, and FAANG-adjacent companies. Each includes the hidden grading criterion — the thing that separates a hire from a "strong no hire."
Core Concepts and Rendering
1. Explain the React reconciliation algorithm and how the virtual DOM works.
What the interviewer grades: Conceptual depth beyond surface-level. They want to hear: React builds a virtual DOM tree, diffs it against the previous tree (O(n) with heuristics — same component type = reconcile, different type = remount), and applies the minimal patch to the real DOM. The heuristics are key: React assumes components of the same type produce the same structure (helps it skip subtrees). Candidates who say "the virtual DOM is a copy of the real DOM and React updates it efficiently" are at beginner level — they haven't studied how React makes it fast.
2. What is the Fiber architecture, and why did React introduce it?
What the interviewer grades: Whether you understand React's internals at a level that lets you predict behavior. Fiber = React's reimplementation of the reconciler (React 16+). Key properties: work can be paused, resumed, and prioritized (cooperative scheduling); renders are split into a work phase (interruptible) and a commit phase (synchronous, non-interruptible); enables Concurrent Mode features like useTransition and useDeferredValue. Before Fiber, reconciliation was synchronous and recursive — a slow render blocked the main thread and janked the UI.
3. What happens when you call setState (or a state setter from useState) inside a React component?
What the interviewer grades: Scheduling and batching knowledge. The answer in React 18: all state updates are batched by default (even inside setTimeout, Promise.then, and native event handlers — this changed from React 17). Batching means multiple setState calls in the same event or async block produce one re-render. After state is set, React schedules a re-render (does not re-render synchronously inline). The component re-renders with the new state value; state is NOT mutated in place.
4. Explain the difference between controlled and uncontrolled components. When would you choose uncontrolled?
What the interviewer grades: Pragmatic judgment, not just definitions. Controlled = React state is the source of truth (every keystroke triggers setState + re-render). Uncontrolled = DOM is the source of truth (you read via ref when needed). Choose uncontrolled for: file inputs (always uncontrolled), high-frequency inputs where re-rendering every keystroke is expensive (debounce or blur-read pattern), and integrating with non-React libraries that manage their own DOM. The senior answer includes when NOT to fight React's data flow.
5. Why does React warn about "each child in a list should have a unique key"? What happens if you use the index as a key?
What the interviewer grades: Understanding of reconciliation impact. Keys let React identify which items changed, were added, or were removed — so it can reconcile efficiently. Using array index as key is safe only when the list is static and never reordered. When items can be reordered, moved, or deleted, index-as-key causes React to diff incorrectly — components maintain stale state (a text input at index 2 keeps its old value when the item at index 2 changes), and React misses the chance to reuse DOM nodes. Real-world bugs from this are subtle and hard to debug.
Hooks
6. Explain the rules of hooks and why they exist.
What the interviewer grades: The WHY behind the rules. Rules: (1) only call hooks at the top level — not inside conditionals, loops, or nested functions; (2) only call hooks from React function components or custom hooks. WHY: React tracks hook state by the order hooks are called. If you call useState conditionally, the order can change between renders and React maps the wrong state to the wrong hook. This is an implementation constraint, not a best-practice suggestion — violating it causes corrupted state.
7. What is the difference between useEffect, useLayoutEffect, and useInsertionEffect?
What the interviewer grades: Render timing precision. useEffect: runs after the browser has painted — correct for data fetching, subscriptions, analytics. useLayoutEffect: runs after DOM mutations but before paint — correct for reading DOM measurements that affect layout (getBoundingClientRect) or synchronously updating the DOM to avoid flicker. useInsertionEffect: runs before DOM mutations — only for CSS-in-JS libraries injecting <style> tags (prevents style flashing). Most developers should use useEffect; reaching for useLayoutEffect is a signal you've operated at a level where paint timing matters.
8. How does useCallback work, and when should you NOT use it?
What the interviewer grades: Knowing that over-optimization is also a bug. useCallback(fn, deps) returns a memoized version of fn that only changes when deps change. Use it when: passing a callback to a child wrapped in React.memo (prevents child re-render when parent re-renders). Do NOT use it when: the child isn't memoized (the memoized callback is useless overhead), or the function is trivial (the memoization cost exceeds the re-render cost). Most useCallback usage in the wild is premature optimization. The senior answer: profile before memoizing.
9. Explain how useMemo differs from useCallback. Give a real example of when you'd use each.
What the interviewer grades: Concrete application, not just definitions. useMemo(fn, deps) memoizes the result of a computation; useCallback(fn, deps) memoizes the function itself. Real useMemo example: an expensive data transformation (filtering + sorting a 10K-row dataset) that only needs to rerun when the dataset or filter changes — wrapping it prevents re-running on every render. Real useCallback example: an onSubmit handler passed to a memoized <Form> component — memoizing prevents Form from re-rendering when the parent re-renders for unrelated reasons.
10. How do you avoid stale closures in useEffect?
What the interviewer grades: A surprisingly common production bug that trips up developers at all levels. Stale closure = the function closed over an old value of a variable because it was captured at the time the effect was created. Solutions: (1) include the variable in the dependency array (most common fix); (2) use a ref to hold a mutable value that effects can read without being stale (useRef + useEffect pattern for callbacks); (3) use the functional update form of setState (setCount(c => c + 1) instead of setCount(count + 1)) to avoid capturing count. The most common mistake: empty dep array [] with a closure over state that changes.
11. What is useReducer, and when should you prefer it over useState?
What the interviewer grades: State architecture judgment. useReducer(reducer, initialState) = Redux-like local state. Prefer it when: state has multiple sub-values that update together (avoids multiple useState calls that can go out of sync), transitions are complex (next state depends on previous state via action type), you want to separate state logic from component rendering, or you need to dispatch from nested children without prop drilling (combine with Context). Signal of senior thinking: "I use useState for simple scalar values and useReducer when the state machine metaphor fits better."
12. How does useContext affect performance, and how do you mitigate over-rendering?
What the interviewer grades: A real performance gotcha. useContext re-renders ALL consumers when the context value changes — even if the consumer only uses one field of a large context object. Mitigation strategies: (1) split contexts by update frequency (auth context separate from theme context separate from cart context); (2) memoize the context value (useMemo); (3) use a state management library that provides selector-based subscriptions (Zustand, Jotai); (4) use context composition patterns. Candidates who say "just use Context instead of Redux" without knowing the performance implications aren't ready to build production apps.
Performance
13. You have a React app that re-renders too frequently. How do you debug and fix it?
What the interviewer grades: Systematic performance debugging discipline. Tools: React DevTools Profiler (highlights which components re-rendered and why), why-did-you-render library (logs unnecessary re-renders to console). Diagnosis: identify the components rendering too often → find what triggered the render (parent re-render? Context? New object/array reference?). Fixes: React.memo for components that re-render with same props, useMemo/useCallback for referential stability of objects/functions, context splitting, state colocation (move state down to where it's used). Signal: candidates who profile first, fix second.
14. What is React's Concurrent Mode, and what problems does it solve?
What the interviewer grades: Understanding of React 18's most important change. Concurrent Mode = React can work on multiple versions of the UI at the same time, and can interrupt rendering to handle higher-priority updates. Problems solved: long renders no longer block user input (typing in a search box doesn't freeze while React renders results), loading states can show while new content renders in the background (useTransition), stale content can show while new data loads (useDeferredValue). Enabling it: ReactDOM.createRoot() (React 18 default). Candidates who say "Concurrent Mode is still experimental" are behind — it shipped in React 18 in 2022.
15. How does React.lazy and Suspense work for code splitting?
What the interviewer grades: Bundle optimization knowledge. React.lazy(() => import('./Component')) = dynamic import wrapped for React. On first render, React suspends (throws a Promise), Suspense catches it and renders the fallback, when the import resolves React renders the component. Use cases: route-level splitting (most impactful — lazy-load entire page components), heavy component splitting (rich text editor, charts). Gotcha: React.lazy only works for default exports; for named exports, you need a re-export wrapper.
16. What is the key prop's role in performance optimization beyond just list rendering?
What the interviewer grades: Advanced reconciliation knowledge. Beyond lists, key can force a component to remount (reset state) when a prop changes. Example: <UserProfile key={userId} userId={userId} /> — when userId changes, React unmounts the old component and mounts a new one with fresh state, instead of trying to reconcile. This is a deliberate design pattern to avoid complex useEffect reset logic. Using key as a reset mechanism is a senior React pattern most developers don't know.
State Management
17. When would you choose Zustand over Redux Toolkit? When would you choose neither?
What the interviewer grades: Opinionated pragmatism. Zustand = minimal API, no boilerplate, selector-based subscriptions (consumers only re-render when their selected slice changes), easy to use outside components. Redux Toolkit = structured, excellent DevTools (time-travel debugging), better for large teams needing conventions. Choose neither = when React's own state (useState + Context) is sufficient — most apps are over-engineered with global state. Canonical answer: Zustand for most mid-size apps; RTK for large teams or apps with complex, interdependent state; neither if you don't need it.
18. How do you handle server state vs. client state in a React application?
What the interviewer grades: The React Query / SWR mental model. Server state (remote data that can go stale) has different requirements than client state (local UI state): caching, background refetch, optimistic updates, error/loading states, deduplication. Libraries like React Query (TanStack Query) handle server state correctly out of the box; using Redux to store server state is usually a sign you're fighting the paradigm. Client state (modal open/closed, selected tab) belongs in useState or useReducer, not in a server-state library.
19. How would you implement optimistic updates?
What the interviewer grades: UX sophistication and error handling discipline. Optimistic update = apply the change to the UI before the server confirms, then reconcile when the response arrives. Implementation with React Query: useMutation with onMutate (apply the optimistic update + snapshot old data), onError (rollback to snapshot), onSettled (invalidate the query to refetch real data). The key is the rollback: an optimistic update without a rollback path is a guaranteed bug. Senior candidates mention the UX implication: show a loading indicator only on subsequent retries, not the first attempt.
Architecture and Advanced Patterns
20. Explain the compound component pattern. When is it appropriate?
What the interviewer grades: API design thinking. Compound components = multiple components that share implicit state via context (e.g., <Select>, <Select.Option>, <Select.Label>). Appropriate when: you need flexible composition of a UI primitive without exposing all variants through a single component's prop API, the components are always used together, and internal state needs to be shared. Example: <Tabs>, <Tabs.List>, <Tabs.Tab>, <Tabs.Panel> — each piece knows which tab is selected without prop-drilling. Inappropriate when: you just need a simple component with a few props.
21. How would you design a React component library that's tree-shakeable and accessible?
What the interviewer grades: Platform thinking. Tree-shakeability: ES module exports (named, not barrel-file default), avoid side effects in module scope, ensure bundler config preserves module format. Accessibility: semantic HTML first, ARIA roles only when semantic HTML is insufficient, keyboard navigation (onKeyDown handlers for custom interactive elements), focus management for modals/dialogs (focus trap, restore focus on close), color contrast (not your job in the component but your job to not bake inaccessible defaults). Tools: Radix UI primitives as a starting point for accessible unstyled components.
22. How do you handle error boundaries in React?
What the interviewer grades: Error handling maturity. Error boundaries = class components that implement componentDidCatch and getDerivedStateFromError — they catch errors in their subtree and render a fallback. Key limitations: error boundaries do NOT catch errors in event handlers (use try/catch), async code (use try/catch in async functions), server-side rendering, or the error boundary itself. Granularity matters: one error boundary for the whole app is insufficient — wrap critical UI sections independently so an error in the sidebar doesn't kill the main content. React's react-error-boundary package adds hooks support.
23. What are React Server Components (RSC), and how do they change the component model?
What the interviewer grades: Whether you're following the 2024-2026 React ecosystem evolution. RSC = components that render on the server only — they can access databases, file systems, and secrets directly, never ship their code to the browser, and can stream HTML to the client. Client components = today's components (interactive, can use hooks, event handlers). The mental model shift: the default is server; add "use client" to opt into client-side interactivity. RSC reduces bundle size (server-only code never ships) and eliminates client-side data fetching waterfalls for initial render. Next.js App Router is the primary RSC runtime today.
24. How would you implement an accessible modal dialog from scratch?
What the interviewer grades: Accessibility engineering depth, not just awareness. Required: (1) focus trap — keyboard focus stays inside the modal while open (Tab cycles within); (2) focus management — focus moves to the modal on open, returns to trigger on close; (3) role="dialog", aria-modal="true", aria-labelledby pointing to the modal title; (4) Escape closes the modal; (5) clicking outside closes the modal; (6) scroll lock on the body. Candidates who answer "I'd use a library" are fine — but they should know what the library does under the hood. Libraries: Radix UI Dialog, Headless UI Dialog.
25. How do you structure a large React application to avoid becoming unmaintainable?
What the interviewer grades: Architecture thinking at scale. Patterns: feature-based folder structure (not type-based — colocate component, styles, tests, types, hooks for a feature); clear layering (UI components vs. data-fetching hooks vs. business logic functions); avoid deeply nested prop drilling (Context or state management for cross-cutting concerns); consistent naming; colocate tests with source. The real answer: structure follows the team's mental model of the product — there's no universal right answer, but "no structure" always goes wrong after 20+ components.
Testing
26. How do you test a React component that fetches data?
What the interviewer grades: Testing philosophy (what to test and how). Best approach in 2026: React Testing Library + MSW (Mock Service Worker) for intercepting network requests — tests exercise real component behavior with real (mocked) data, not implementation details. Avoid: testing that a specific fetch function was called (ties tests to implementation); mocking modules wholesale (too far from production behavior). Key principle from RTL: test what the user sees and does, not internal component state.
27. What's the difference between unit tests, integration tests, and end-to-end tests in a React context?
What the interviewer grades: Testing pyramid judgment. Unit: a single function or hook in isolation (custom hook tested with renderHook, pure utility function tested with Jest). Integration: a component tree with real child components and mocked network (RTL + MSW — the sweet spot for most React testing). E2E: a real browser driving real user flows (Playwright, Cypress — critical paths only, slow and expensive). Strong answer: 70% integration, 20% unit, 10% E2E — and the reasoning behind it.
Real-world and System Design
28. How would you build a real-time collaborative editor in React?
What the interviewer grades: Systems thinking + React architecture together. Key concerns: operational transform (OT) or CRDT for conflict resolution (e.g., Yjs); WebSocket for real-time updates; state management that can apply patches without full re-renders; cursor positions for multiple users; debounced saves to server; optimistic local updates with server reconciliation. React's role: rendering the document and user cursors; the collaboration logic lives in a separate layer. You don't need to implement CRDTs — but you should know they exist and why naive "last write wins" breaks.
29. How would you implement infinite scroll that doesn't kill performance?
What the interviewer grades: Performance engineering in a real product context. Naive infinite scroll = keep appending DOM nodes → memory grows → scroll performance degrades. Fix = virtual/windowed rendering (react-virtual, react-window): only render visible items + a small buffer; as user scrolls, recycle DOM nodes for new content. Additional concerns: intersection observer for load trigger (not scroll event listener), abort controllers for cancelling inflight requests when user scrolls fast, empty state, error state, and end-of-list handling.
30. You need to build a search-as-you-type feature. How do you architect it?
What the interviewer grades: UX + performance + React integration. Concerns: debounce the input (300ms) to avoid a request per keystroke; cancel inflight requests when a new query arrives (AbortController); loading state shown after debounce triggers (not instantly); empty state vs. no-results state; keyboard navigation of results (accessible); caching recent queries (React Query with keepPreviousData to avoid flash of empty on back-navigation). Bonus: mention useTransition for keeping the input responsive while React renders the results list.
Behavioral and Philosophy
31. What's the biggest React performance mistake you've seen in production, and how did you fix it?
What the interviewer grades: Real production experience and ownership. Any specific, honest answer is good. Common real-world answers: context causing entire app re-renders on every state change (split contexts, added memoization); rendering thousands of DOM nodes in a list (added virtualization); expensive computation in render without memoization (added useMemo); image-heavy pages without lazy loading (added loading="lazy" + Intersection Observer). The test: they'll ask follow-up questions about your specific fix — have the details ready.
32. How do you stay current with React as it evolves (RSC, Actions, the compiler)?
What the interviewer grades: Self-directed learning and signal vs. noise filtering. "I follow every RFC" is fine; "I wait until a pattern is adopted by a framework I use, then learn it hands-on" is more pragmatic and also valid. What they're really checking: are you aware of React Server Components and the compiler? These are the biggest shifts since Hooks and have already shipped in production frameworks (Next.js App Router, Remix). Not knowing they exist is a signal you haven't followed React for the last 2 years.
33. When would you NOT use React?
What the interviewer grades: Engineering judgment beyond the tool you're hired to use. Good answers: highly interactive, performance-critical UIs (games, canvas-heavy apps) where React's overhead is meaningful → use vanilla JS, WebGL; simple, content-heavy pages with minimal interactivity → server-rendered HTML + a little JS (Astro, plain HTML); web components that need to work across frameworks → custom elements. Candidates who say "React is always the right choice" haven't thought about the trade-offs.
34. Describe a time you had to refactor a large React component. How did you approach it?
What the interviewer grades: Disciplined refactoring, not just "I cleaned it up." Expected: you read the component fully before touching it, identified what it was responsible for (and found it was doing too many things), extracted custom hooks for data/logic, split the render into smaller components, added tests before refactoring (if they didn't exist), and verified behavior was unchanged. Red flag: "I rewrote it from scratch" without a story of why incremental refactor wasn't viable.
35. What's your mental model for deciding when to split a component?
What the interviewer grades: Design intuition. Rules they expect to hear: split when a component has two unrelated reasons to re-render; split when part of the component can be reused elsewhere; split when the component is hard to test in isolation; split when the JSX is too long to reason about in one read. Don't split just to hit an arbitrary line count. The principle: a component should do one thing and be writable in one sitting without losing track of what it does.
FAQ
What React topics are most tested in senior interviews? Performance (reconciliation, memoization, virtualization), hooks internals (stale closures, dependency arrays, useLayoutEffect timing), state management trade-offs (when to use Redux vs. Zustand vs. Context), React 18 Concurrent features (useTransition, useDeferredValue), and React Server Components. Interviewers at senior level care less about "do you know the API" and more about "can you reason about rendering behavior and performance."
How do I prepare for React coding rounds? Build components from scratch without documentation open: autocomplete search boxes, draggable lists, multi-step forms with validation, data tables with sorting/filtering/pagination. These cover the full range — event handling, state management, performance, accessibility. Build each one multiple times until you can do it in 30 minutes.
Is TypeScript expected in React interviews? At most companies in 2026, yes — TypeScript is the default for React development and you'll be expected to type components, props, hooks return values, and generic utilities. Know React.FC vs. function signature with explicit return type, typed useRef patterns, and ComponentProps<typeof X> utility types.
What's the best way to practise React interview questions? Build things and explain your decisions out loud. The interview tests whether you can articulate the WHY — why this hook, why this architecture, why this performance fix. Reading answers builds recognition; speaking them builds retrieval. Run mock interviews where you narrate your component design in real time.