15 React Interview Questions & Answers (2026)
Comprehensive React interview questions covering hooks, performance, state management, and modern React patterns. With detailed answers to help you prepare for frontend engineering interviews in 2026.
1. What is the virtual DOM and how does React use it?
The virtual DOM is a lightweight in-memory representation of the real DOM. When state changes, React builds a new virtual DOM tree and diffs it against the previous one (reconciliation). Only the actual differences are applied to the real DOM — this is more efficient than re-rendering everything. React's reconciliation algorithm (Fiber in React 16+) can pause, abort, and resume work, enabling concurrent features like Suspense and transitions.
2. Explain the rules of hooks.
Hooks have two rules: (1) Only call hooks at the top level — not inside loops, conditions, or nested functions. This ensures hooks are called in the same order every render, so React can correctly associate state with the right hook. (2) Only call hooks in React function components or custom hooks — not in regular JavaScript functions or class components. The react-hooks ESLint plugin enforces these rules automatically.
3. What is useEffect and what are common mistakes with it?
useEffect runs side effects after rendering — data fetching, subscriptions, manually updating the DOM. The dependency array controls when it re-runs: empty array runs once after mount; omitting it runs after every render; with dependencies runs when those values change. Common mistakes: omitting dependencies (stale closure bug), forgetting to return a cleanup function for subscriptions/timers (memory leak), and using it for derived state that could be computed directly during render.
4. What is React.memo and when should you use it?
React.memo is a higher-order component that memoizes a functional component — it skips re-rendering if props haven't changed (using shallow comparison). Use it for components that receive the same props frequently and are expensive to render. Be careful: if you pass a new object or function reference on every parent render, React.memo won't help. Pair it with useCallback for callbacks and useMemo for object props.
5. Explain controlled vs uncontrolled components.
A controlled component has its form state managed by React — the input value is bound to state via value prop, and updates via onChange. React is the 'single source of truth.' An uncontrolled component stores its own state in the DOM — you access it via a ref. Controlled components offer more predictability and are easier to validate; uncontrolled components are simpler for quick forms and when integrating non-React code.
6. What is the Context API and when would you use it over Redux?
Context API provides a way to share values across the component tree without passing props at every level. Use it for values that rarely change — authentication state, theme, locale. Avoid using Context for high-frequency state updates (like animations or form state) because every Consumer re-renders when context value changes. Redux offers more structure, devtools, middleware (redux-thunk, redux-saga), and performance optimizations for large apps with complex state interactions.
7. What is code splitting in React and how do you implement it?
Code splitting breaks your bundle into smaller chunks that load on demand, improving initial page load time. React.lazy() and Suspense enable component-level code splitting: const MyComponent = React.lazy(() => import('./MyComponent')). Wrap it in a Suspense boundary with a fallback UI. Next.js does route-level code splitting automatically. Dynamic imports (import()) can also split non-component code.
8. What are custom hooks and why are they useful?
Custom hooks are functions that start with 'use' and can call other hooks. They extract stateful logic from a component so it can be reused. Examples: useFetch (data fetching logic), useDebounce (debounced value), useLocalStorage (syncing state with localStorage). Custom hooks improve readability by naming complex logic, and improve testability by separating logic from UI.
9. How does React handle keys in lists and why are they important?
Keys help React identify which items in a list have changed, been added, or removed. During reconciliation, React uses keys to match elements from the old and new tree. Without keys (or with index as key), React may re-render or reorder items incorrectly, especially when items have state. Always use a stable, unique identifier from your data as the key — not the array index when the list can be reordered.
10. What is the difference between useRef and useState?
useState triggers a re-render when its value changes. useRef holds a mutable value that persists across renders but does not trigger re-renders when mutated. Use useRef for: accessing DOM elements directly (ref.current), storing a previous state/prop value, holding a timer/interval ID, or any value you want to persist without causing a re-render. The .current property is mutable — changes to it are immediate and synchronous.
11. Explain the difference between useLayoutEffect and useEffect.
useEffect runs asynchronously after the browser has painted the screen. useLayoutEffect runs synchronously after DOM mutations but before the browser paints — similar to componentDidMount/componentDidUpdate in class components. Use useLayoutEffect when your effect needs to read layout or make DOM changes that must happen before the user sees the paint, to avoid visual flicker. For most side effects, useEffect is the right choice.
12. What are higher-order components (HOCs) and how have they been replaced?
HOCs are functions that take a component and return a new component with additional behavior — a common pattern before hooks (e.g., withRouter, connect from Redux). They added wrapper components to the tree, making debugging harder. Hooks largely replaced HOCs by moving reusable logic into custom hooks instead of wrapping components. Hooks result in flatter component trees and simpler code. Understanding HOCs matters when working with older codebases.
13. What is Suspense in React and what can it do?
Suspense allows components to 'suspend' rendering while waiting for something (like data or a lazy-loaded component) and shows a fallback UI instead. Originally only for lazy loading, React 18 expanded Suspense to work with data fetching through frameworks (Next.js, Relay). Combined with concurrent features (useTransition, useDeferredValue), Suspense enables non-blocking UI updates where React can show stale content while new data loads, avoiding layout shifts.
14. How do you optimize re-renders in a React application?
Key strategies: (1) Lift state down — put state as close to where it's used as possible to avoid unnecessary re-renders up the tree. (2) Use React.memo for expensive components. (3) Memoize callbacks with useCallback and computed values with useMemo. (4) Split context into multiple contexts so consumers only re-render when their relevant data changes. (5) Use virtualization (react-window, react-virtual) for long lists. (6) Profile first with React DevTools Profiler before optimizing.
15. What is the difference between React 17 and React 18?
React 18 introduced concurrent rendering — React can work on multiple tasks simultaneously and interrupt rendering to handle urgent updates. Key additions: Automatic Batching (multiple setState calls in async code now batch by default), Transitions (useTransition, startTransition for marking non-urgent updates), new root API (createRoot), Suspense for data fetching, and useId hook. React Server Components were introduced as an experimental feature becoming stable with Next.js App Router.
Practice React interviews with AI
Get personalized React question sets based on your experience level and receive AI feedback on your answers with Resumly's interview prep tool.
Start interview prepMore interview guides
Frequently Asked Questions
What React topics are most important for interviews in 2026?
Focus on hooks (useState, useEffect, useCallback, useMemo, useRef, useContext), the virtual DOM and reconciliation, performance optimization (memoization, code splitting), component patterns (compound components, render props, HOCs), state management (Context, Redux, Zustand), and React Server Components if the role involves Next.js. Understanding why React works the way it does matters more than memorizing API signatures.
Should I learn class components for React interviews in 2026?
You should understand class components conceptually and know their lifecycle methods (componentDidMount, componentDidUpdate, componentWillUnmount), but new React codebases almost exclusively use functional components with hooks. In interviews, demonstrate you understand both, but be fluent in functional component patterns — that's where the industry has moved.
What is the difference between useMemo and useCallback?
useMemo memoizes a computed value — it recalculates only when its dependencies change. useCallback memoizes a function reference — it returns the same function instance across renders unless dependencies change. useCallback is useful when passing callbacks to child components wrapped in React.memo, preventing unnecessary re-renders. Both are optimizations — don't add them preemptively, only when you've measured a performance problem.
What are React Server Components?
React Server Components (RSC) render on the server and send HTML (not JavaScript) to the client, reducing bundle size and enabling direct database access without an API layer. They cannot use state or browser APIs. Client Components (marked 'use client') retain interactivity. Next.js App Router uses RSC by default. This is the biggest architectural shift in React since hooks and is highly relevant for 2026 interviews.
How do I handle global state in React without Redux?
Context API with useContext handles simple global state (theme, auth user, locale) well. For complex client state, Zustand is popular for its minimal boilerplate and good TypeScript support. Jotai uses atomic state (similar to Recoil). React Query / TanStack Query manages server state (data fetching, caching, synchronization) separately from client state. The trend is to separate server state from client state rather than putting everything in one global store.