Top 62 React Interview Questions and Answers (2026)

The 62 React questions interviewers actually ask, with direct answers, working JSX, and what the interviewer is listening for. Grouped for freshers, intermediate, and experienced rounds.

62 questions with answers

What Is React?

Key Takeaways

  • React is a JavaScript library for building user interfaces from small, reusable components that describe what the UI should look like for a given state.
  • It uses a virtual DOM and a diffing step so you write declarative code and React works out the minimal real-DOM updates.
  • Interviews test how well you understand rendering, hooks, and state flow, not whether you've memorized every API.
  • This page is a question bank: work your tier first, read one tier up, and say answers out loud because delivery is evaluated too.

React is an open-source JavaScript library for building user interfaces, created at Facebook and first released in 2013. You build UIs from components: self-contained functions that take inputs (props) and return a description of what to render. React is declarative, so you describe the UI for a given state and React handles the DOM updates through a virtual DOM and a reconciliation step. That model is why React scales from a single widget to large single-page applications. In interviews, React questions probe understanding of rendering, hooks, and how state flows through a component tree, not memorized API trivia. This page collects the 62 questions that come up most, each with a direct answer and working JSX. If you're still building fundamentals, the official React documentation at react.dev is the canonical path; increasingly the first front-end round is a live AI coding interview, so pair this bank with our AI interview preparation guides for the format side.

62Questions with answers on this page
3Difficulty tiers: freshers, intermediate, experienced
24Runnable JSX snippets you can practice from
45-60 minTypical length of a React technical round

Watch: React in 100 Seconds

Video: React in 100 Seconds (Fireship, YouTube)

Test yourself and earn a certificate

10 quick questions. Score 70%+ to download your React certificate.

Jump to quiz

All Questions on This Page

62 questions
React Interview Questions for Freshers
  1. 1. What is React and what problem does it solve?
  2. 2. What is JSX and how does the browser run it?
  3. 3. What are the main rules of writing JSX?
  4. 4. What is a component and what are props?
  5. 5. What is the difference between props and state?
  6. 6. How does the useState hook work?
  7. 7. Why should you sometimes pass a function to a state setter?
  8. 8. Why must you update React state immutably?
  9. 9. How do you handle events in React?
  10. 10. How do you conditionally render UI in React?
  11. 11. How do you render a list, and why does each item need a key?
  12. 12. What is the difference between controlled and uncontrolled components?
  13. 13. Why use useState instead of a regular variable for changing data?
  14. 14. What are React hooks?
  15. 15. What is a React Fragment and why use one?
  16. 16. What is one-way data flow in React?
  17. 17. How do you set default values for props?
  18. 18. What is the children prop?
  19. 19. What is a single-page application, and how does React fit?
  20. 20. What is the virtual DOM?
  21. 21. How do you split components across files?
  22. 22. What is StrictMode?
  23. 23. When is it acceptable to use the array index as a key?
  24. 24. How do you style a React component?
React Intermediate Interview Questions
  1. 25. How does useEffect work, including its dependency array and cleanup?
  2. 26. What are the common useEffect mistakes?
  3. 27. What is useRef and what are its two main uses?
  4. 28. What is the difference between useMemo and useCallback?
  5. 29. When should you actually reach for memoization?
  6. 30. What are the rules of hooks and why do they exist?
  7. 31. What is a custom hook and when do you write one?
  8. 32. What is the difference between useEffect and useLayoutEffect?
  9. 33. What is the Context API and what problem does it solve?
  10. 34. What does 'lifting state up' mean?
  11. 35. How does React favor composition over inheritance?
  12. 36. What does React.memo do and when does it help?
  13. 37. How does React's reconciliation work?
  14. 38. What causes a component to re-render?
  15. 39. What is useReducer and when is it better than useState?
  16. 40. How do you fetch data in a React component?
  17. 41. What is an error boundary?
  18. 42. What is a React portal and when do you use one?
  19. 43. How do you handle a form with multiple fields in React?
  20. 44. What is prop drilling and how do you avoid it?
  21. 45. How can changing a key force a component to reset?
React Interview Questions for Experienced Developers
  1. 46. What happens between calling a setter and the screen updating?
  2. 47. What did concurrent rendering change in React?
  3. 48. What is Suspense and what is it for?
  4. 49. What are React Server Components?
  5. 50. How do you decide where state should live and what tool manages it?
  6. 51. What are the real trade-offs of memoization in React?
  7. 52. What makes a good custom hook, and how do you avoid common pitfalls?
  8. 53. A list of thousands of rows is janky. How do you fix it?
  9. 54. How do you test React components, and what does Testing Library encourage?
  10. 55. Why does StrictMode double-invoke functions, and what bugs does it surface?
  11. 56. How do you expose a DOM node or imperative method from a component?
  12. 57. How do higher-order components and render props compare to hooks?
  13. 58. How does React batch state updates?
  14. 59. Context causes too many re-renders. How do you fix it?
  15. 60. How do you code-split a React app and why?
  16. 61. Design exercise: build a paginated data table component.
  17. 62. Design exercise: build a debounced search input that queries an API.

React Interview Questions for Freshers

Freshers24 questions

The fundamentals every entry-level round checks. If any answer here surprises you, that's your study list.

Q1. What is React and what problem does it solve?

React is a JavaScript library for building user interfaces out of components: functions that take inputs and return a description of the UI. It's declarative, so you say what the UI should look like for a given state and React figures out the DOM changes.

The problem it solves is keeping a complex UI in sync with changing data. Instead of hand-writing DOM updates, you update state and React re-renders the affected parts, which makes large interactive apps far easier to reason about.

Key point: A one-line definition plus the word 'declarative' and why it matters beats a memorized feature list. Interviewers open with this to hear how you organize an answer.

Watch a deeper explanation

Video: Learn React In 30 Minutes (Web Dev Simplified, YouTube)

Q2. What is JSX and how does the browser run it?

JSX is a syntax extension that lets you write markup-like code inside JavaScript. It looks like HTML but it's really syntactic sugar for function calls that create element objects.

Browsers don't understand JSX. A compiler like Babel or the framework's build step transforms each JSX tag into a React.createElement call, or the newer automatic jsx runtime, before the code ships.

jsx
const el = <h1 className="title">Hello</h1>;

// compiles to roughly:
const el = React.createElement("h1", { className: "title" }, "Hello");

Key point: The follow-up is 'why className instead of class?'. JSX is JavaScript, and class is a reserved word, so React uses className.

Q3. What are the main rules of writing JSX?

Return a single root element (or a Fragment), close every tag, and use camelCase for attributes like className and onClick. Embed JavaScript expressions with curly braces, but only expressions, not statements.

You can't put an if statement inside JSX, but you can use a ternary or logical && for conditional rendering. A Fragment (<>...</>) groups siblings without adding a wrapper node.

jsx
function Greeting({ name, isVip }) {
  return (
    <>
      <h1>Hello, {name}</h1>
      {isVip && <span>VIP</span>}
    </>
  );
}

Q4. What is a component and what are props?

A component is a reusable piece of UI written as a function that returns JSX. Props are the inputs a parent passes down to a component, received as a single object argument.

Props are read-only from the child's point of view: a component must never modify its own props. This one-way data flow, parent to child, is what makes React apps predictable.

jsx
function Avatar({ name, src }) {
  return <img src={src} alt={name} />;
}

function Profile() {
  return <Avatar name="Asha" src="/asha.png" />;
}

Key point: Say 'props are read-only' explicitly. It sets up the state question and shows you understand one-way data flow.

Watch a deeper explanation

Video: React Course - Beginner's Tutorial for React JavaScript Library (freeCodeCamp.org, YouTube)

Q5. What is the difference between props and state?

Props are passed in from a parent and are read-only to the component that receives them. State is data a component owns and manages internally, updated through a setter that triggers a re-render.

The rule of thumb: if a value is passed from above and never changed here, it's a prop; if the component changes it over time in response to interaction, it's state.

PropsState
OwnerParent componentThe component itself
Mutable here?No (read-only)Yes, via the setter
Triggers re-renderWhen parent passes new propsWhen you call the setter
Typical useConfiguration passed downData that changes over time

Key point: This is one of the most asked React questions. Have the 'passed down vs owned here' one-liner ready to say instantly.

Q6. How does the useState hook work?

useState returns a pair: the current state value and a setter function. Calling the setter schedules a re-render with the new value. The argument to useState is the initial value, used only on the first render.

React remembers state between renders by call order, which is why you call useState at the top level and never inside conditions. Each call to the component reads the latest stored value.

jsx
import { useState } from "react";

function Counter() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(count + 1)}>
      Clicked {count} times
    </button>
  );
}

Key point: Mention that the initial value is used only on the first render. Candidates who think it re-applies every render write subtle bugs, and interviewers probe for it.

Watch a deeper explanation

Video: Learn useState In 15 Minutes - React Hooks Explained (Web Dev Simplified, YouTube)

Q7. Why should you sometimes pass a function to a state setter?

When the new state depends on the previous state, pass an updater function: setCount(c => c + 1). React guarantees it receives the latest value, which matters because state updates can batch and the closed-over variable may be stale.

If you call setCount(count + 1) three times in a row with a plain value, they all read the same count and you get one increment. The functional form gives three.

jsx
// stale: all three read the same count
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);   // net: +1

// correct: each gets the latest
setCount(c => c + 1);
setCount(c => c + 1);
setCount(c => c + 1);   // net: +3

Key point: Mentioning batching and stale closures here is a strong signal. It's the reason the functional updater exists.

Q8. Why must you update React state immutably?

React decides whether to re-render by comparing the previous and next state references. If you mutate an object or array in place, the reference doesn't change, so React may skip the update entirely.

Always create a new object or array instead: spread the old one and change what you need. This is why you see {...state, key: value} and [...list, item] everywhere in React code.

jsx
// wrong: mutates, same reference, may not re-render
user.name = "Ben";
setUser(user);

// right: new object
setUser({ ...user, name: "Ben" });

// right: new array
setItems([...items, newItem]);

Q9. How do you handle events in React?

You pass a function to a camelCased event prop like onClick or onChange. React wraps native events in a synthetic event for cross-browser consistency, and you get the event object as the handler's argument.

Pass the function itself, not its call: onClick={handleClick}, not onClick={handleClick()}. Use an arrow function when you need to pass arguments: onClick={() => remove(id)}.

jsx
function Item({ id, onRemove }) {
  return (
    <button onClick={() => onRemove(id)}>
      Remove
    </button>
  );
}

Key point: The classic beginner bug is onClick={handleClick()}, which calls the function during render. Interviewers watch for this.

Q10. How do you conditionally render UI in React?

Because JSX is JavaScript, you use ordinary expressions: a ternary for either/or, logical && to render something or nothing, or an early return for whole-component branches.

One trap: && with a number like 0 renders the 0 on screen, because 0 is falsy but still a valid React child. Guard with a boolean (count > 0 && ...) instead of a bare count.

jsx
function Status({ loading, count }) {
  if (loading) return <Spinner />;
  return (
    <div>
      {count > 0 ? <List /> : <Empty />}
      {count > 0 && <Badge value={count} />}
    </div>
  );
}

Q11. How do you render a list, and why does each item need a key?

You map an array to elements: items.map(item => <Row key={item.id} ... />). React needs a key on each element so it can match items to their previous instances across renders and update only what changed.

Keys must be stable and unique among siblings. Using the array index as a key breaks when the list reorders or items are inserted, because the index no longer identifies the same item, which corrupts component state.

jsx
function TodoList({ todos }) {
  return (
    <ul>
      {todos.map(todo => (
        <li key={todo.id}>{todo.text}</li>
      ))}
    </ul>
  );
}

Key point: The follow-up is always 'why not the index?'. Have the reorder-and-insert failure ready to describe.

Q12. What is the difference between controlled and uncontrolled components?

In a controlled component, form input values live in React state and every change flows through onChange, so React is the single source of truth. In an uncontrolled component, the DOM holds the value and you read it with a ref when you need it.

Controlled inputs are the default recommendation because they make validation, conditional disabling, and derived UI straightforward. Uncontrolled inputs are handy for simple forms or integrating non-React widgets.

jsx
function ControlledInput() {
  const [value, setValue] = useState("");
  return (
    <input
      value={value}
      onChange={e => setValue(e.target.value)}
    />
  );
}
ControlledUncontrolled
Source of truthReact stateThe DOM node
Read valueFrom state directlyVia a ref
Validation on changeEasyHarder
Best forMost formsSimple or non-React widgets

Q13. Why use useState instead of a regular variable for changing data?

A plain variable declared in a component resets to its initial value on every render, and changing it doesn't tell React to re-render. State survives across renders and, when updated through the setter, schedules a new render.

So the two jobs state does that a variable can't: it persists between renders, and it triggers the UI to update. If a value needs neither, a plain constant is fine and cheaper.

Q14. What are React hooks?

Hooks are functions that let function components use React features that used to require classes: state (useState), side effects (useEffect), context (useContext), refs (useRef), and more. Their names all 'use' comes first.

They arrived in React 16.8 and became the standard way to write components. Before hooks, stateful logic lived in class lifecycle methods; hooks let you organize that logic by concern and share it through custom hooks instead.

jsx
import { useState, useEffect, useRef } from "react";

function Timer() {
  const [seconds, setSeconds] = useState(0);
  useEffect(() => {
    const id = setInterval(() => setSeconds(s => s + 1), 1000);
    return () => clearInterval(id);
  }, []);
  return <span>{seconds}s</span>;
}

Key point: Listing three or four hooks by name and what each does, then saying they replaced class lifecycle methods, is a crisp full answer.

Q15. What is a React Fragment and why use one?

A Fragment lets you return multiple elements from a component without wrapping them in an extra DOM node like a div. You write it as <>...</> or <React.Fragment>...</React.Fragment>.

It matters for valid HTML (a table row can't be wrapped in a div) and for keeping the DOM flat, which avoids styling and layout headaches from unnecessary wrappers.

jsx
function Columns() {
  return (
    <>
      <td>Name</td>
      <td>Role</td>
    </>
  );
}

Q16. What is one-way data flow in React?

Data in React flows in one direction: down the component tree, from parent to child through props. A child can't reach up and change its parent's data directly; it can only call a callback the parent passed down.

This makes apps predictable: to find why something on screen has a value, you trace props up toward where the state lives. When a child needs to change shared data, the parent owns the state and hands down both the value and a setter.

Key point: Contrast it with two-way binding from other frameworks. Saying 'state flows down, events flow up' captures the whole model in one line.

Q17. How do you set default values for props?

With function components, you set defaults right in the destructuring of the parameter: function Button({ variant = 'primary' }). If the prop is undefined, the default applies.

This replaced the older defaultProps static on function components, which React is phasing out. Destructuring defaults are the current standard and read clearly.

jsx
function Button({ label, variant = "primary", disabled = false }) {
  return (
    <button className={variant} disabled={disabled}>
      {label}
    </button>
  );
}

Q18. What is the children prop?

children is a special prop holding whatever you nest between a component's opening and closing tags. It lets you build wrapper and layout components that don't know their contents in advance.

This is the basis of composition in React: a Card or Modal renders {children} in the right place, and callers pass any JSX they want inside.

jsx
function Card({ children }) {
  return <div className="card">{children}</div>;
}

// usage
<Card>
  <h2>Title</h2>
  <p>Body text</p>
</Card>

Q19. What is a single-page application, and how does React fit?

A single-page application loads one HTML shell and then updates the view with JavaScript as the user moves around, instead of requesting a fresh page from the server each time. Navigation feels instant because only data changes, not the whole document.

React renders and re-renders those views on the client. A router like React Router maps URLs to components so the address bar and back button still work, all without full page reloads.

Q20. What is the virtual DOM?

The virtual DOM is a lightweight in-memory description of your UI: plain JavaScript objects that mirror the element tree. When state changes, React builds a new virtual tree and compares it to the previous one.

From that comparison React computes the minimal set of real DOM changes and applies just those. You write code as if re-rendering everything, and React makes the actual updates cheap.

Key point: Don't oversell the virtual DOM as 'always faster'. It's about a simpler programming model with acceptable performance, which is the honest framing interviewers prefer.

Q21. How do you split components across files?

Each component usually lives in its own file and is exported, then imported where it's used. A file can have one default export and any number of named exports.

Keeping one component per file makes the tree easy to read and reuse. The import path and the export style (default vs named) just have to match on both ends.

jsx
// Avatar.jsx
export default function Avatar({ src }) {
  return <img src={src} alt="" />;
}

// Profile.jsx
import Avatar from "./Avatar";

Q22. What is StrictMode?

StrictMode is a development-only wrapper that helps you catch problems early. It intentionally double-invokes component render functions and effect setup so impure logic and missing cleanup show up loudly.

It renders nothing itself and has zero effect in production builds. Seeing an effect or a console log fire twice in development is usually StrictMode doing its job, not a bug.

Q23. When is it acceptable to use the array index as a key?

Only when the list is static: it never reorders, items are never inserted or removed from the middle, and the items have no local state or uncontrolled inputs. In that narrow case the index is stable enough.

Any list that can change order or size needs a stable ID from the data. The safe default is to always prefer a real ID and treat index keys as a smell you can defend.

Q24. How do you style a React component?

Common options: plain CSS or CSS Modules imported into the component, utility classes like Tailwind via className, CSS-in-JS libraries, or the inline style prop which takes a camelCased object.

The inline style prop is fine for a handful of dynamic values but shouldn't replace a stylesheet. Note style takes an object ({{ color: 'red' }}) with camelCased keys, not a string.

jsx
function Badge({ active }) {
  return (
    <span
      className="badge"
      style={{ opacity: active ? 1 : 0.4 }}
    >
      New
    </span>
  );
}
Back to question list

React Intermediate Interview Questions

Intermediate21 questions

For candidates with working experience: hook mechanics, rendering behavior, and the questions that separate users from understanders.

Q25. How does useEffect work, including its dependency array and cleanup?

useEffect runs a side effect after the render is committed to the screen. The dependency array controls when it re-runs: with a list of values, it re-runs whenever one changed; with an empty array, it runs once after mount; with no array at all, it runs after every render.

If the effect returns a function, that's the cleanup. React runs it before the next effect and on unmount, which is where you remove event listeners, clear timers, or cancel subscriptions.

jsx
useEffect(() => {
  const id = setInterval(tick, 1000);
  return () => clearInterval(id);   // cleanup
}, []);   // run once on mount

The useEffect lifecycle

1Render
component returns JSX; effect not run yet
2Commit
React updates the DOM to match
3Run effect
if a dependency changed since last time
4Cleanup
runs before the next effect and on unmount

Effects run after paint, not during render, which is why you never read the just-updated DOM synchronously inside render.

Key point: The follow-up is always about the dependency array. Explaining the three cases (list, empty, omitted) confidently is the bar.

Watch a deeper explanation

Video: Learn useEffect In 13 Minutes (Web Dev Simplified, YouTube)

Q26. What are the common useEffect mistakes?

The big ones: omitting dependencies the effect actually uses (leading to stale values), causing an infinite loop by setting state that's also a dependency without a guard, forgetting cleanup so listeners and timers leak, and putting logic in an effect that could just be computed during render.

A useful reframe interviewers like: many effects shouldn't exist. If you're syncing state derived from props, compute it during render instead. Effects are for synchronizing with systems outside React, network, DOM, subscriptions.

Key point: Saying 'you might not need an effect' out loud signals current React understanding. Deriving values during render beats an effect that copies props into state.

Q27. What is useRef and what are its two main uses?

useRef returns a mutable object with a .current property that persists across renders and, notably, changing it does not trigger a re-render. First use: hold a reference to a DOM node so you can focus it, measure it, or scroll it.

Second use: store a mutable value that outlives renders but shouldn't cause re-renders, like a timer ID, a previous value, or a mutable counter. If changing a value should update the UI, that's state, not a ref.

jsx
function SearchBox() {
  const inputRef = useRef(null);
  useEffect(() => {
    inputRef.current.focus();   // focus on mount
  }, []);
  return <input ref={inputRef} />;
}

Key point: The distinction interviewers probe: ref changes don't re-render, state changes do. Pick ref when the value is not rendered.

Watch a deeper explanation

Video: Learn useRef in 11 Minutes (Web Dev Simplified, YouTube)

Q28. What is the difference between useMemo and useCallback?

useMemo memoizes a computed value: it re-runs the expensive function only when a dependency changes, otherwise it returns the cached result. useCallback memoizes a function reference so it stays identical across renders while its dependencies are unchanged.

They're the same idea applied to different things. useCallback(fn, deps) is literally useMemo(() => fn, deps). You reach for useCallback when a stable function reference matters, for example passing a callback to a memoized child.

jsx
const total = useMemo(
  () => items.reduce((s, i) => s + i.price, 0),
  [items]
);

const handleClick = useCallback(
  () => onSelect(id),
  [onSelect, id]
);
useMemouseCallback
ReturnsA cached valueA cached function reference
Use whenA computation is expensiveA stable function reference matters
EquivalentuseMemo(() => v, d)useMemo(() => fn, d)
Overuse costExtra comparisons, complexityExtra comparisons, complexity

Key point: Say that both have a cost and shouldn't be sprinkled everywhere. Premature memoization is a real anti-pattern interviewers watch for.

Watch a deeper explanation

Video: Learn useMemo In 10 Minutes (Web Dev Simplified, YouTube)

Q29. When should you actually reach for memoization?

When you've measured a real cost: a component that renders often and does expensive work, or a large list where an unstable prop keeps breaking a memoized child. React.memo, useMemo, and useCallback all trade a little memory and complexity for skipped work.

They're not free and they're not automatic wins. Adding them everywhere adds comparison overhead and noise. Profile first with the React DevTools Profiler, then memoize the hot path.

Re-render cost of a heavy child: without vs with React.memo

Relative render work when a parent re-renders 100 times and the child's props rarely change (log scale). Numbers illustrate the pattern, not a benchmark.

No memo
10,000 render units
With React.memo
100 render units
  • No memo: Child re-renders every parent render
  • With React.memo: Child re-renders only when props change

Key point: The honest answer is 'measure first'. Reflexively wrapping everything in useMemo indicates cargo-culting, not judgment.

Q30. What are the rules of hooks and why do they exist?

Two rules: only call hooks at the top level of a component or another hook, never inside conditions, loops, or nested functions; and only call them from React function components or custom hooks, not regular functions.

The reason is how React tracks hook state: it relies on the call order being identical on every render to match each useState or useEffect to its stored slot. A conditional hook shifts that order and corrupts the mapping, which is why the linter enforces this.

Key point: Explaining the 'call order' mechanism, not just reciting the rules, is what separates memorization from understanding here.

Watch a deeper explanation

Video: 10 React Hooks Explained // Plus Build your own from Scratch (Fireship, YouTube)

Q31. What is a custom hook and when do you write one?

A custom hook is a function whose name starts with 'use' and which calls other hooks to package reusable stateful logic. It lets you share behavior, like fetching data or reading window size, without repeating the same useState and useEffect wiring.

It shares logic, not state: each component that calls the hook gets its own independent state. Write one when the same hook combination shows up in two or more components.

jsx
function useToggle(initial = false) {
  const [on, setOn] = useState(initial);
  const toggle = useCallback(() => setOn(o => !o), []);
  return [on, toggle];
}

// usage
const [isOpen, toggleOpen] = useToggle();

Watch a deeper explanation

Video: Learn Custom Hooks In 10 Minutes (Web Dev Simplified, YouTube)

Q32. What is the difference between useEffect and useLayoutEffect?

Both run after render, but at different moments. useEffect runs asynchronously after the browser has painted, so it doesn't block the visual update. useLayoutEffect runs synchronously after the DOM is updated but before paint, so it can read layout and change it without the user seeing a flicker.

The default is useEffect. Reach for useLayoutEffect only when you must measure the DOM (size, scroll position) and adjust it before the frame is shown, for example positioning a tooltip. Overusing it blocks painting and hurts perceived speed.

jsx
useLayoutEffect(() => {
  const { height } = ref.current.getBoundingClientRect();
  setTooltipTop(-height);   // adjusted before paint, no flicker
}, []);

Key point: The one-line answer: useEffect after paint, useLayoutEffect before paint. Add 'default to useEffect' so you don't sound like you reach for the blocking one first.

Q33. What is the Context API and what problem does it solve?

Context lets a parent provide a value that any descendant can read, without passing props through every level in between. It solves prop drilling, threading a value through components that don't need it just to reach one that does.

You create a context, wrap a subtree in its Provider with a value, and read it with useContext. It fits truly global-ish data: theme, current user, locale. It's not a general state manager, and every consumer re-renders when the value changes.

jsx
const ThemeContext = createContext("light");

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar() {
  const theme = useContext(ThemeContext);
  return <div className={theme}>...</div>;
}

Key point: The trap is calling Context a state manager. Note that changing the value re-renders all consumers, which is why you split contexts or memoize the value.

Watch a deeper explanation

Video: Learn useContext In 13 Minutes (Web Dev Simplified, YouTube)

Q34. What does 'lifting state up' mean?

When two sibling components need to share or stay in sync with the same data, you move that state up to their closest common parent and pass it down as props, along with a setter callback. The parent becomes the single source of truth.

This keeps data flowing one way: state lives in one place, children receive it and report changes upward through callbacks. It's the standard fix for 'these two components need the same value'.

jsx
function Parent() {
  const [query, setQuery] = useState('');
  return (
    <>
      <SearchInput value={query} onChange={setQuery} />
      <Results query={query} />
    </>
  );
}

Q35. How does React favor composition over inheritance?

React apps reuse code by composing components, passing children and props, rather than by extending base component classes. A generic Dialog takes children and renders them; a specialized dialog just renders a Dialog with specific content inside.

The React team explicitly recommends composition, and in practice inheritance almost never comes up. Props, children, and custom hooks cover the reuse cases inheritance would.

jsx
function Dialog({ title, children }) {
  return (
    <div className="dialog">
      <h2>{title}</h2>
      {children}
    </div>
  );
}

function ConfirmDialog() {
  return (
    <Dialog title="Confirm">
      <button>Yes</button>
    </Dialog>
  );
}

Q36. What does React.memo do and when does it help?

React.memo wraps a component so that if its props are shallowly equal to the previous render, React skips re-rendering it and reuses the last output. It's the component-level equivalent of caching a render.

It helps when a component re-renders often with the same props and its render is non-trivial. It backfires if props are new objects or functions every render (the shallow check always fails), which is where useCallback and useMemo on the parent come in.

jsx
const Row = React.memo(function Row({ label }) {
  return <li>{label}</li>;
});
// Row re-renders only when `label` changes

Key point: The follow-up connects the tools: React.memo on the child is defeated by unstable function props, so pair it with useCallback on the parent.

Q37. How does React's reconciliation work?

When state changes, React renders a new element tree and diffs it against the previous one. Rather than a costly full tree comparison, it uses heuristics: elements of different types are replaced wholesale, and children are matched by key.

That's why key matters: it tells React which child in the new list corresponds to which in the old list, so it can move and reuse DOM nodes instead of recreating them. The output of reconciliation is the minimal set of real DOM operations.

Key point: Tying reconciliation back to keys shows you understand why the key rule exists, not just that it does.

Q38. What causes a component to re-render?

Three triggers: its own state changed (a setter was called), a context it consumes changed, or its parent re-rendered. That last one surprises people: a parent re-render re-renders all its children by default, even if their props didn't change.

Note that a re-render doesn't always mean DOM changes. React re-runs the component function and diffs the result; if the output is identical, no DOM work happens. That's why 'extra renders' aren't automatically a performance problem.

Q39. What is useReducer and when is it better than useState?

useReducer manages state through a reducer function that takes the current state and an action and returns the next state. You dispatch actions instead of calling setters directly.

Prefer it over useState when state is complex or the next value depends on the previous in non-trivial ways, when several values update together, or when you want update logic centralized and testable outside the component. Simple independent values stay with useState.

jsx
function reducer(state, action) {
  switch (action.type) {
    case "inc": return { count: state.count + 1 };
    case "reset": return { count: 0 };
    default: return state;
  }
}

const [state, dispatch] = useReducer(reducer, { count: 0 });
// dispatch({ type: "inc" })

Key point: The reducer must stay pure and return new state, not mutate it. Saying 'same input, same output, no side effects' is the detail that indicates real experience.

Q40. How do you fetch data in a React component?

The classic pattern is a useEffect that fetches on mount and stores the result in state, tracking loading and error alongside it. You add cleanup to ignore a response if the component unmounted or the request is stale.

In real apps, most teams use a data library like React Query or SWR, or a framework's built-in loader, because they handle caching, deduping, retries, and stale-while-revalidate that hand-rolled effects miss. Mention that; it indicates production experience.

jsx
useEffect(() => {
  let active = true;
  fetch(`/api/users/${id}`)
    .then(r => r.json())
    .then(data => { if (active) setUser(data); });
  return () => { active = false; };   // ignore stale response
}, [id]);

Key point: Naming a data library (React Query, SWR) and why raw effects fall short (caching, races) is what lifts this above a textbook answer.

Q41. What is an error boundary?

An error boundary is a component that catches JavaScript errors thrown during rendering in its child tree, logs them, and shows a fallback UI instead of crashing the whole app. It uses the lifecycle methods getDerivedStateFromError and componentDidCatch.

Notably, error boundaries are still written as class components, one of the few places classes remain necessary. They don't catch errors in event handlers, async code, or the boundary itself; those you handle with try/catch.

jsx
class ErrorBoundary extends React.Component {
  state = { hasError: false };
  static getDerivedStateFromError() {
    return { hasError: true };
  }
  render() {
    if (this.state.hasError) return <Fallback />;
    return this.props.children;
  }
}

Key point: Mention that boundaries don't catch event-handler or async errors. That boundary awareness is exactly what the question screens for.

Q42. What is a React portal and when do you use one?

createPortal renders children into a different part of the DOM tree, outside the parent component's DOM node, while keeping them in the React tree for props, context, and events. Event bubbling still follows the React tree, not the DOM position.

The typical use is overlays: modals, tooltips, dropdowns that must escape a parent's overflow: hidden or z-index stacking context but still behave like children of the component that owns them.

jsx
function Modal({ children }) {
  return createPortal(
    <div className="overlay">{children}</div>,
    document.body
  );
}

Q43. How do you handle a form with multiple fields in React?

Keep the form values in a single state object and update it immutably on change, using the input's name to know which field to set. One handler can serve every input this way.

On submit, call preventDefault to stop the browser's default navigation, then read from state. For anything beyond a few fields, teams reach for a form library like React Hook Form to handle validation and reduce re-renders.

jsx
function Form() {
  const [values, setValues] = useState({ name: '', email: '' });
  const change = e =>
    setValues(v => ({ ...v, [e.target.name]: e.target.value }));
  return (
    <form onSubmit={e => e.preventDefault()}>
      <input name="name" value={values.name} onChange={change} />
      <input name="email" value={values.email} onChange={change} />
    </form>
  );
}

Q44. What is prop drilling and how do you avoid it?

Prop drilling is passing a prop down through many intermediate components that don't use it, just to reach a deep child. It clutters components with props they only forward.

Fixes, in order of reach: restructure with composition so the data-owner renders the consumer directly, use Context for genuinely shared values like theme or user, or adopt a state library for large cross-cutting state. Reach for the lightest fix that works.

Q45. How can changing a key force a component to reset?

React ties a component's identity to its position and key. Give a component a new key and React unmounts the old instance and mounts a fresh one, resetting all its internal state. Same key, same instance, state preserved.

This is a deliberate technique: keying a form on the selected record ID resets the form cleanly when the user switches records, no manual state-clearing effect needed.

jsx
// switching userId remounts EditForm with fresh state
<EditForm key={userId} userId={userId} />
Back to question list

React Interview Questions for Experienced Developers

Experienced17 questions

advanced rounds probe internals, design judgment, and production scars. Expect every answer here to draw a follow-up.

Q46. What happens between calling a setter and the screen updating?

React works in two phases. In the render phase it calls your component functions to compute the new element tree and reconciles it against the previous one; this phase is pure and can be paused or discarded. In the commit phase it applies the computed changes to the real DOM and then runs layout effects and effects.

Understanding the split explains real behavior: render must be side-effect-free (that's why StrictMode double-invokes it), and effects run in commit, after paint, which is why you can't read updated layout during render.

From setState to pixels

1Trigger
a setter runs and schedules an update
2Render
React re-runs components, builds a new tree
3Reconcile
diff against the previous tree for minimal changes
4Commit
apply DOM changes, then run effects

The render phase is pure and interruptible; the commit phase touches the DOM and is not.

Key point: Framing render as pure and interruptible versus commit as the DOM write is the mental model concurrent features build on.

Q47. What did concurrent rendering change in React?

Concurrent rendering lets React interrupt, pause, and resume the render phase instead of blocking the main thread until a render finishes. It can prepare a new UI in the background and keep the current one responsive, then commit when ready.

You mostly use it through features built on it: useTransition to mark non-urgent updates so typing stays snappy, useDeferredValue to defer expensive derived UI, and Suspense for coordinated loading. The point is prioritizing urgent updates over expensive ones.

jsx
const [isPending, startTransition] = useTransition();

function onType(e) {
  setQuery(e.target.value);           // urgent
  startTransition(() => {
    setResults(search(e.target.value)); // non-urgent
  });
}

Q48. What is Suspense and what is it for?

Suspense lets a component 'wait' for something (code, data) before rendering, showing a declared fallback in the meantime. You wrap part of the tree in <Suspense fallback={...}> and any suspending child triggers the fallback until it's ready.

It started with React.lazy for code-splitting and now underpins data loading in frameworks and server components. The value is declarative loading states: no manual isLoading flags scattered through the tree.

jsx
const Dashboard = React.lazy(() => import("./Dashboard"));

function App() {
  return (
    <Suspense fallback={<Spinner />}>
      <Dashboard />
    </Suspense>
  );
}

Q49. What are React Server Components?

Server Components render on the server and send a serialized description of the UI to the client, never shipping their own JavaScript to the browser. They can read the database or filesystem directly and reduce bundle size, since their code stays on the server.

They interleave with Client Components, which run in the browser and hold interactivity and state (marked with 'use client'). The mental model: server components for data and structure, client components for anything with hooks, events, or browser APIs. Frameworks like Next.js drive most real usage today.

Key point: You're being screened for awareness, not deep production use. Knowing server components can't use state or effects, and why, is the level expected.

Q50. How do you decide where state should live and what tool manages it?

the lightest option and escalate only when you feel the pain comes first. Local useState for component-owned state; lift it to the nearest common parent when siblings share it; Context for a few genuinely global values like theme or auth; a dedicated library only for large, frequently-updated, cross-cutting state.

A key distinction seniors draw: server state (data from an API) and client state (UI state) have different needs. Server state wants caching and revalidation, which is React Query or SWR territory, not a global store. Conflating the two is the common mistake.

State kindReach forWhy
Local UI stateuseState / useReducerOwned by one component
Shared by siblingsLift to common parentOne source of truth, props down
A few global valuesContextAvoids prop drilling for theme, user
Server dataReact Query / SWRCaching, dedupe, revalidation
Large cross-cuttingRedux Toolkit / ZustandStructured global store

Key point: Separating server state from client state is the production signal here. Many candidates default to a global store for API data, which interviewers see as a red flag.

Q51. What are the real trade-offs of memoization in React?

Every memoization adds cost: the comparison of dependencies, the memory for cached values, and the cognitive load of dependency arrays that can go stale or wrong. Applied without a measured need, it often makes things slower and buggier, not faster.

The discipline is to profile with the DevTools Profiler, find components that render often and expensively, and memoize those specifically. It's also worth mentioning that the React team's Compiler aims to automate much of this, which reframes the whole topic.

Q52. What makes a good custom hook, and how do you avoid common pitfalls?

A good custom hook has a focused responsibility, a clear return shape (tuple for two values, object for more), stable references where callers depend on them, and complete effect cleanup. It reads like a small API, not a dumping ground.

Pitfalls: returning new object or function references every render (which breaks consumers' memoization unless you useCallback/useMemo inside), hidden effects that surprise callers, and stale-closure bugs from missing dependencies. Test hooks in isolation to catch these.

Q53. A list of thousands of rows is janky. How do you fix it?

Virtualize it: render only the rows in and near the viewport with a windowing library (react-window, TanStack Virtual) instead of thousands of DOM nodes. That alone usually removes the jank because DOM size, not React, is the bottleneck.

Then supporting fixes: stable keys, memoize row components so unrelated state changes don't re-render every row, memoize the callbacks passed to rows, and move expensive derived data out of render. Measure with the Profiler before and after.

Key point: Leading with virtualization shows you know the real cost is DOM node count, not React overhead. That's the answer this question is built to elicit.

Q54. How do you test React components, and what does Testing Library encourage?

React Testing Library renders components and queries them the way a user would: by role, label, and visible text, then simulates interaction and asserts on what the user sees. It deliberately discourages reaching into implementation details like state or instance internals.

The philosophy is 'test behavior, not implementation', so tests survive refactors. Pair it with a runner like Jest or Vitest, query by accessible role, use userEvent for interactions, and mock network boundaries with something like MSW.

jsx
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";

test("increments", async () => {
  render(<Counter />);
  await userEvent.click(screen.getByRole("button"));
  expect(screen.getByText(/clicked 1/i)).toBeInTheDocument();
});

Q55. Why does StrictMode double-invoke functions, and what bugs does it surface?

In development, StrictMode intentionally runs component bodies twice and mounts, unmounts, then remounts components once, running each effect an extra setup/cleanup cycle. It's not random: it forces impure renders and effects that lack proper cleanup to fail visibly.

Bugs it surfaces: mutating props or module-level state during render, effects that subscribe without unsubscribing, and setup that assumes it runs exactly once. Code that's correct under React's rules survives the double invocation unchanged, which is the point.

Q56. How do you expose a DOM node or imperative method from a component?

To let a parent's ref reach a child's DOM node, forward it. In current React you can accept ref as a normal prop; older code uses forwardRef. When you need to expose specific imperative methods rather than the raw node, use useImperativeHandle to define a small controlled surface.

The caution to voice: imperative handles are an escape hatch. Prefer props and state; reach for this only for genuinely imperative actions like focus, scroll, or media playback that don't fit the declarative model.

jsx
const FancyInput = forwardRef(function FancyInput(props, ref) {
  const inputRef = useRef(null);
  useImperativeHandle(ref, () => ({
    focus: () => inputRef.current.focus(),
  }));
  return <input ref={inputRef} {...props} />;
});

Q57. How do higher-order components and render props compare to hooks?

Higher-order components (a function that takes a component and returns a wrapped one) and render props (a prop that's a function returning UI) were the pre-hooks ways to share stateful logic. Both work but add wrapper nesting and can obscure where props come from.

Hooks replaced most of these cases: a custom hook shares logic without adding to the tree or causing wrapper hell. You still see HOCs in older libraries and for cross-cutting concerns like connecting to a store, so recognizing them matters, but new code reaches for hooks.

Q58. How does React batch state updates?

React groups multiple state updates that happen in the same event into a single re-render, so several setters fire one render, not one each. Since React 18, automatic batching extends this to updates inside promises, timeouts, and native event handlers too, not just React events.

This is why functional updaters matter for dependent updates, and why you occasionally reach for flushSync to force a synchronous update when you must read the DOM immediately after. Knowing 18 broadened batching beyond React events is the detail seniors are expected to have.

Q59. Context causes too many re-renders. How do you fix it?

Every consumer re-renders when a context value changes, and a fresh object literal as the value re-renders consumers on every provider render. First fix: memoize the value with useMemo so its reference is stable.

Structural fixes: split one big context into several narrow ones so a change to one slice doesn't re-render consumers of another, separate rarely-changing from frequently-changing values, or move to a store that supports selector-based subscriptions (Zustand, Redux) when the state is large and hot.

jsx
// stable value: consumers re-render only when user or theme changes
const value = useMemo(
  () => ({ user, theme }),
  [user, theme]
);
return <AppContext.Provider value={value}>{children}</AppContext.Provider>;

Key point: The unmemoized value literal is the bug interviewers plant. Spotting it, then proposing context splitting, is the full-credit answer.

Q60. How do you code-split a React app and why?

Split the bundle so users download only the code for the route or feature they're using, not the whole app upfront. React.lazy plus dynamic import() loads a component on demand, wrapped in Suspense for the loading fallback; routers and frameworks do route-level splitting automatically.

The payoff is faster initial load and better Core Web Vitals, since a smaller first bundle improves load and interaction readiness. The judgment is splitting at meaningful boundaries (routes, heavy modals, rarely-used features) rather than over-splitting into many tiny chunks.

jsx
const Settings = React.lazy(() => import("./Settings"));

<Suspense fallback={<Spinner />}>
  <Settings />
</Suspense>

Q61. Design exercise: build a paginated data table component.

Clarify first: server-side or client-side pagination, page size fixed or user-set, and whether the total count is known. Then shape the state: current page, page size, and either the current page's rows (server) or the full dataset sliced in a memo (client). Fetch keyed on page and size with a useEffect or a data hook, tracking loading and error.

Close on the edges the key signal is: disable Previous on page one and Next on the last page, keep controls usable during loading (show a pending state, don't unmount), reset to page one when filters change, and reflect the page in the URL so it's shareable and survives refresh.

jsx
function usePagination(fetchPage) {
  const [page, setPage] = useState(1);
  const [data, setData] = useState({ rows: [], total: 0 });
  useEffect(() => {
    let active = true;
    fetchPage(page).then(d => { if (active) setData(d); });
    return () => { active = false; };
  }, [page, fetchPage]);
  const pages = Math.ceil(data.total / 20);
  return { page, setPage, pages, rows: data.rows };
}

Key point: The structure clarify, state, fetch, edges is what's evaluated. Volunteering the disable-at-boundaries and reset-on-filter details indicates production experience.

Back to question list

Why React? React vs Angular, Vue, and Svelte

React wins when you want a large ecosystem, a huge hiring pool, and the freedom to assemble your own stack from routing to state management. It's a library, not a full framework, so it stays flexible but leaves more decisions to you. Angular hands you an opinionated, batteries-included framework; Vue sits between the two with a gentle learning curve; Svelte compiles components away for less runtime overhead. Knowing these trade-offs out loud is itself an interview signal: it shows you pick tools on merits, not habit.

FrameworkModelBest atWatch out for
ReactLibrary, virtual DOMLarge ecosystem, flexible stacks, big hiring poolYou assemble routing/state yourself
AngularFull framework, DIOpinionated enterprise apps, one blessed waySteeper curve, more boilerplate
VueFramework, reactiveGentle learning curve, approachable templatesSmaller job market than React
SvelteCompiler, no VDOMSmall bundles, less runtime overheadYounger ecosystem, fewer libraries

How to Prepare for a React Interview

Prepare in layers, and practice out loud. Most React rounds move from concept questions to live component building to a design or debugging discussion, so rehearse each stage rather than only reading answers.

  • Master your tier's concepts until you can explain them without notes, then read one tier up for the stretch questions.
  • Type and run every snippet in a sandbox; modifying working components cements them far faster than reading.
  • Practice thinking aloud while building a small component with a timer, because your process, not just the final render is the technical point.
  • Take the quiz on this page to find weak spots, then revisit those questions before the real round.

The typical React interview flow

1Recruiter or phone screen
background, motivation, a few concept checks
2Technical concepts
JSX, props vs state, hooks, rendering, keys
3Live component build
build and explain a component under observation
4Design or debugging
state management trade-offs, performance, reading unfamiliar code

Earlier rounds increasingly run as AI coding interviews. The concepts on this page are what gets probed at every stage.

Test Yourself: React Quiz

Ready to test your React knowledge?

10 questions, about 6 minutes. Score 70% or higher to earn a shareable certificate.

10 questions Instant feedback Free certificate on 70%+

Frequently  Asked  Questions

Which React topics should I prioritize before a technical round?

Prioritize the areas that change real decisions: fundamentals, practical tasks, debugging, trade-offs, and evidence. The highest-value questions are tied to a project example, a validation check, or a failure mode.

Are these questions enough to pass a React interview?

They cover the question-answer portion well, but most React rounds also include a live build: writing a component under observation while explaining your thinking. building small components out loud with a timer is the practice path. Our AI coding interview prep guide covers that format, including how automated evaluation reads your process.

Do these answers assume class or function components?

Function components with hooks, throughout. Hooks arrived in React 16.8 and are the standard for new code; class components still exist in older codebases, so you should recognize lifecycle methods, but the question expects you to reach for hooks. When in doubt in an interview, say you're answering with modern function components.

How long does it take to prepare for a React interview?

If you use React at work or in study, one to two weeks of an hour a day covers this bank with practice builds. Starting colder, plan three to four weeks and write components daily; reading answers without building them is how preparation quietly fails.

Do interviewers ask exactly these questions?

The concepts repeat far more reliably than the exact wording. Interviewers rephrase, chain follow-ups, and push toward whatever you claim confidence in. Prepare the underlying ideas, rendering, hook rules, state flow, keys, and the phrasing takes care of itself.

Is there a way to test my React knowledge?

Yes. The quiz on this page scores you as you go and explains every answer, so you find your weak spots fast. Pass the threshold and you can download a shareable certificate with your name and score, free and with no sign-up. It is the quickest way to check yourself before the real round.

From the team that builds coding interviews

Hyring builds the AI Coding Interviewer that runs live technical rounds in 20+ languages, and front-end React work is one of the most common. These questions reflect what actually gets asked and evaluated inside the interviews we host for 5,000+ HR teams.

See how the AI Coding Interviewer works

Sources

Adithyan RKWritten by Adithyan RK
Surya N
Fact-checked by Surya N
Published on: 25 Apr 2026Last updated: 26 Jun 2026
Share: