Coding Interviews

React Interview Questions and Answers With Working Code

Prepare for React interview questions with concise explanations, working code, common follow-ups, and a practical component exercise you can trace.

The Stealth Interview Team10 min read
React Interview Questions and Answers With Working Code

React interview questions rarely stop at definitions. You usually need to predict renders, explain state ownership, repair a broken effect, and build a component while describing the trade-offs.

A strong answer connects React’s public model to the JavaScript underneath it. The working code matters, but so does your explanation of why it works.

How React Interviews Test More Than React Syntax#

React interviews usually combine conceptual questions, code reading, debugging, and component implementation.

For each question, structure your answer in four parts:

  1. Define the behavior. State what React or the browser will do.
  2. Explain the mechanism. Describe rendering, closures, identity, or effect synchronization.
  3. Identify the trade-off. Explain when the approach becomes awkward or expensive.
  4. Give a small example. Use code or trace a render sequence.

Suppose you are asked why an effect sees an old state value. “The dependency array is wrong” may identify the symptom. A better answer explains that each render creates new closures. The effect callback retains values from the render that created it.

Separate React knowledge from JavaScript knowledge as you reason:

  • React decides when to render and reconcile.
  • JavaScript determines closure behavior and object identity.
  • The browser controls timers, network requests, and input events.
  • React effects synchronize your component with those external systems.

This separation helps when the first diagnosis fails. You can move through the layers instead of changing hooks at random.

React Fundamentals Interview Questions#

The core React model is components receiving inputs and returning a description of the interface.

What are components, props, state, and JSX?#

A component is a function that React can render. Props are inputs supplied by its parent. State is component-owned data that persists between renders and can schedule another render.

JSX is syntax transformed into element creation calls. It is not a template language with its own runtime state.

JavaScript
function Greeting({ name, isAdmin }) {
  const label = isAdmin ? `Admin: ${name}` : name;

  return React.createElement(
    "p",
    null,
    `Hello, ${label}`
  );
}

label is derived from props. It should not be copied into state. Duplicating it would create another value that could become inconsistent with name or isAdmin.

What causes a component to render?#

A component can render when:

  • Its state receives an update.
  • Its parent renders.
  • A context it reads changes.
  • An external store subscription reports a change.

A render does not guarantee a DOM change. Rendering calculates the next element tree. React then reconciles that tree against the previous one and commits only the necessary host changes.

That distinction matters in code-reading questions. A component function may execute even when its visible output remains the same.

Why do keys matter?#

Keys identify siblings across list renders. Stable keys let React associate existing component state and DOM nodes with the correct item.

JavaScript
function ResultList({ results }) {
  return React.createElement(
    "ul",
    null,
    results.map((result) =>
      React.createElement("li", { key: result.id }, result.name)
    )
  );
}

An array index is risky when items can be inserted, deleted, filtered, or reordered. The index describes a position, not the item’s identity.

Likely follow-ups include:

  • What happens to child state after its key changes?
  • Why must keys be unique only among siblings?
  • When is an index acceptable?
  • How does one-way data flow affect state ownership?

One-way data flow means parents pass data down. Children communicate changes through callbacks or shared state mechanisms. It makes the source of a value easier to trace.

Hooks Questions: useState, useEffect, useRef, and Closures#

Hooks questions test whether you understand renders as snapshots rather than mutable component instances.

How do state updates work?#

Calling a setter requests a future render. It does not rewrite the state variable inside the current function call.

JavaScript
function incrementTwice(setCount) {
  setCount((current) => current + 1);
  setCount((current) => current + 1);
}

Functional updaters are appropriate when the next value depends on the previous value. React can queue those updater functions and apply them in order. React also batches many updates so it can avoid unnecessary intermediate renders.

Code such as setCount(count + 1) captures count from the current render. Repeating it can request the same next value twice rather than incrementing from the latest queued value.

When should you use an effect?#

Use an effect to synchronize with something outside React. Examples include network requests, timers, subscriptions, and browser APIs.

Do not use an effect to derive an ordinary display value:

JavaScript
function Price({ subtotal, tax }) {
  const total = subtotal + tax;

  return React.createElement(
    "output",
    null,
    total.toFixed(2)
  );
}

An effect’s dependency list should include reactive values read by the effect. Cleanup must undo the synchronization established by that effect: remove a listener, clear a timer, unsubscribe, or cancel a request.

This is the important point in React hooks interview questions: dependencies are not a manual scheduling wish list. They describe which captured values the synchronization depends on.

What is a stale closure?#

A stale closure occurs when a callback keeps values from an older render.

JavaScript
function scheduleLog(count) {
  window.setTimeout(() => {
    console.log(count);
  }, 500);
}

That callback logs the count supplied when scheduleLog ran. Depending on the task, you can fix stale behavior by using a functional state updater, declaring correct dependencies, recreating the callback, or reading a current value from a ref.

A ref persists across renders but changing ref.current does not schedule a render. State does. Use state for values that affect visible output. Use a ref for mutable information that rendering does not need, such as a timer identifier or the latest request token.

Component Design and State Management Questions#

Good React state management starts by choosing one authoritative owner for each value.

Keep state as close as possible to the components that need it. Lift it to the nearest common parent when multiple children must read or update the same value. Consider context or an external store only when the sharing pattern justifies broader access.

Controlled vs uncontrolled components#

A controlled input receives its current value from React state and reports edits through a callback. An uncontrolled input leaves its current value in the DOM and is usually read through a ref or form submission.

Controlled inputs make validation, conditional behavior, and coordinated updates explicit. Uncontrolled inputs can reduce wiring for simple forms or integrations with non-React code. Neither choice is universally correct.

Context, reducers, composition, and custom hooks#

  • Context distributes a value through a subtree without passing it through every intermediate component.
  • Reducers centralize related state transitions and make event-driven updates explicit.
  • Composition lets a component accept children or renderable pieces instead of accumulating configuration flags.
  • Custom hooks reuse stateful behavior. They do not share state unless they connect to a shared external source.

Consider a prompt to build a selectable product list. Before writing code, assign responsibilities:

  • The parent owns the products and selected product identifier.
  • The list renders products and reports selection.
  • Each row displays one product.
  • A details component derives the selected product from the identifier.
  • Loading and request errors belong near the code performing the request.

Do not store both selectedId and selectedProduct if one can be derived from the other. That duplicated state can contradict itself after the product list changes.

React Performance and Debugging Questions#

React performance interview questions should start with observed work, not automatic memoization.

React.memo can skip a child render when its props are shallowly equal. useMemo can retain a calculated value between renders. useCallback can retain a function reference. All introduce dependencies and maintenance cost.

Referential equality explains many failed optimizations:

JavaScript
function Parent({ items }) {
  const options = { compact: true };

  return React.createElement(ResultList, {
    items,
    options
  });
}

options is a new object on every render. A memoized child sees a changed prop reference. You could move a constant outside the component or memoize it if profiling shows the child render matters.

Use this debugging procedure:

  1. Reproduce the bug with the smallest reliable sequence.
  2. Record relevant props, state, and request identifiers.
  3. Trace which components render and why.
  4. Inspect effect setup and cleanup.
  5. Profile the exact interaction before adding memoization.
  6. Change one cause and repeat the reproduction.

Common failures include mutating an array before setting state, omitting effect dependencies, missing useEffect cleanup, using unstable keys, and allowing an old request to overwrite newer results.

Memoization does not repair incorrect state ownership or stale effects. Fix correctness first.

Worked Coding Exercise: Build a Debounced Search Component#

A debounced search component should control the input, wait before requesting, expose loading and errors, and prevent stale responses from winning.

JavaScript
function DebouncedSearch({ search, delay = 300 }) {
  const [query, setQuery] = React.useState("");
  const [status, setStatus] = React.useState("idle");
  const [results, setResults] = React.useState([]);

  React.useEffect(() => {
    const term = query.trim();
    if (!term) {
      setResults([]);
      setStatus("idle");
      return;
    }

    const controller = new AbortController();
    const timer = window.setTimeout(async () => {
      setStatus("loading");
      try {
        const next = await search(term, controller.signal);
        setResults(next);
        setStatus("success");
      } catch (error) {
        if (error.name !== "AbortError") setStatus("error");
      }
    }, delay);

    return () => {
      window.clearTimeout(timer);
      controller.abort();
    };
  }, [query, delay, search]);

  return React.createElement(
    "section",
    null,
    React.createElement("input", {
      value: query,
      onChange: (event) => setQuery(event.target.value),
      "aria-label": "Search"
    }),
    status === "loading"
      ? React.createElement("p", null, "Loading")
      : null,
    status === "error"
      ? React.createElement("p", { role: "alert" }, "Search failed")
      : null,
    React.createElement(
      "ul",
      null,
      results.map((item) =>
        React.createElement("li", { key: item.id }, item.name)
      )
    )
  );
}

After rapid input changes, the sequence is:

  1. The input event updates query.
  2. React renders with the new value.
  3. React cleans up the previous effect, clearing its timer or aborting its request.
  4. The new effect schedules another timer.
  5. Only a query left unchanged for the delay starts a request.
  6. Cleanup prevents an older request from committing after a newer query.

The search function should have a stable reference. If a parent recreates it on every render, the effect restarts. You can define it outside the parent, pass a stable callback, or redesign the prop contract.

Test empty input, rapid typing, request failure, unmounting during a request, and results arriving out of order. A reusable useDebouncedSearch hook could own the query status, effect, cancellation, and results while leaving rendering to the component.

JavaScript Questions That Commonly Appear Beside React#

JavaScript fundamentals often explain the React bug you are being asked to diagnose.

  • Closures: An event handler or timer may retain state from an older render.
  • Event loop: Promise callbacks and timers run later, after the current call stack finishes.
  • Promises: Requests can resolve out of order and require cancellation or stale-response protection.
  • Destructuring: Default values and renamed fields affect how props are read.
  • Immutability: Mutating an existing object can preserve its identity and hide a meaningful change.
  • Array methods: map, filter, and non-mutating updates help produce new collections.
  • Object identity: Two objects with identical fields are still different references.

For example, items.sort() mutates the existing array. Prefer copying when state must remain unchanged:

JavaScript
function sortByName(items) {
  return [...items].sort((left, right) =>
    left.name.localeCompare(right.name)
  );
}

This operation takes O(n log n) time and O(n) additional space for the copied array.

Use the coding interview guides on the blog for broader language and complexity review. The LeetCode reference is useful when you also need practice explaining data structures and algorithms aloud.

How to Practice React Interview Questions Effectively#

Practice should make your reasoning visible, not just produce finished components.

Use this compact sequence:

  1. Explain components, props, state, reconciliation, and keys aloud.
  2. Predict the output of hook and closure examples before running them.
  3. Repair effects with missing dependencies or cleanup.
  4. Design state ownership from a written component requirement.
  5. Debug mutation, unstable identity, and request races.
  6. Build one small component under time constraints.
  7. Explain its renders, effects, edge cases, and trade-offs.

Evaluate each answer against four checks:

  • Correctness: Does the behavior match React and JavaScript semantics?
  • Clarity: Can you explain the render and effect sequence without vague phrases?
  • Edge cases: What happens on empty input, failure, unmount, reorder, or rapid updates?
  • Trade-offs: Why did you choose state, a ref, context, memoization, or an effect?

For react coding interview questions, narrate before you optimize. State who owns each value. Identify what triggers a render. Describe what cleanup reverses. If your first approach fails, use that model to locate the broken assumption rather than rewriting the component blindly.

Frequently asked questions

What causes a React component to render?
A component can render when its state receives an update, its parent renders, a context it reads changes, or an external store subscription reports a change. Rendering does not guarantee a DOM change.
Why do keys matter in React lists?
Keys identify siblings across list renders, allowing React to associate component state and DOM nodes with the correct items. Array indexes are risky when items can be inserted, deleted, filtered, or reordered.
When should you use useEffect in React?
Use an effect to synchronize with systems outside React, such as network requests, timers, subscriptions, and browser APIs. Ordinary display values should usually be derived during rendering instead.
What is a stale closure in React?
A stale closure occurs when a callback retains values from an older render. Depending on the task, it can be addressed with functional state updates, correct dependencies, a recreated callback, or a ref holding the current value.
What is the difference between state and a ref?
State is appropriate for values that affect visible output because updates can schedule a render. A ref persists across renders, but changing its current value does not schedule a render.

Keep reading

Ace your next coding interview

Stealth Interview is a desktop app for macOS and Windows that reads the problem off your screen and answers with a working solution, a step-by-step explanation and its time and space complexity — while staying invisible to screen sharing.

Get Stealth Interview