React interview questions: rendering, re-renders and reconciliation

Reviewed by Mark Dickie · Last updated

6 questions on this page you can answer and see marked on the spot. Go to the first one

React is a JavaScript library for building user interfaces out of components. Rendering questions test how that component tree gets updated, not only how to draw it. Interviewers often ask what triggers a re-render and why keys matter in lists. An answer that stops at "state changes cause re-renders" rarely survives the first follow-up.

Which React rendering topics come up most often?

TopicWhat to be able to explain
Render vs commitReact calls your component function to produce JSX, then writes DOM changes in a separate commit phase.
Keys and reconciliationA key tells React which list item is the same element across renders. Using the array index as a key can reuse the wrong DOM node after a reorder.
React.memoSkips re-rendering a child when its props are shallow-equal to the last render. It does nothing for props that are new objects or functions on every parent render.
useMemo and useCallbackKeep object and function identities stable between renders, which only pays off when the receiving child is memoized.
State placementMoving state down into the component that uses it limits how much of the tree re-renders when that value changes.
ContextEvery consumer of a context re-renders when its value changes, even if the consumer only reads one field.
startTransition and useDeferredValueMark updates as interruptible so typing stays responsive while a heavy list re-renders.
StrictModeIn development, it calls component functions twice to expose render logic that has side effects.

How do you trace a slow re-render in a React app?

  1. Record the slow interaction in the React DevTools Profiler.
  2. Enable "Record why each component rendered" in the Profiler settings.
  3. Sort by self time and check which components re-rendered because a prop or context value changed by reference.
  4. Fix the cause you found: memoize the child, move the state down, or split the context so fewer consumers depend on the changing value.

Key facts

  • Tarmac has 24 React interview questions on this topic, 10 of them on this page, at difficulty 1–5 of 5.
  • Tarmac tracked 2,154 job postings asking for React in September 2026.
  • Roles asking for React advertise a median base salary of US$178,325, across 672 job postings as of September 2026.
  • Tarmac last reviewed these React interview questions on 26 October 2026.

At a glance

Questions10 shown · 24 in the bank
Difficulty1–5 of 5
FormatsTrue / false, Code output, Find the bug, Multiple answer, Ordering, Short answer, Flashcard, Multiple choice

What you'll review

  1. reconciliation
  2. keys

Practice questions

Try one before you open the answer. Pick an option and press Check; it's marked on the spot.

When rendering a list in React, providing a unique key prop for each item helps React identify which items have changed, been added, or been removed during reconciliation.#

Options

Show answer

True. The key prop gives React a stable identity for each list item so the reconciler can efficiently detect additions, removals, and reordering between renders — without it, React falls back to comparing by position, which can cause incorrect updates or unnecessary re-mounts.

Why:

The key prop gives React a stable identity for each list item so it can match elements between renders without relying solely on index position. When keys are unique and stable, React can reorder, add, or remove items efficiently. Using array indices as keys is an anti-pattern when the list order can change, but a key is not the same as a component's id prop — it's a special hint consumed by React and not passed down to the component.

What is rendered to the screen (as visible UI text) the first time this component mounts in a standard React 18 production environment (no Strict Mode)?#

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  console.log('render');

  return (
    <div>
      <p>{count}</p>
      <button onClick={() => setCount(count)}>Click me</button>
    </div>
  );
}

export default Counter;
Show answer
0
Click me
Why:

On the initial mount the component renders once. useState(0) initialises count to 0, so <p>{count}</p> displays 0 and the button displays its label Click me. The question asks only about the visible DOM output on first mount, which is unambiguous regardless of Strict Mode or bailout behaviour: the user sees 0 and the button text Click me.

The following component is supposed to render a numbered list of fruits. However, after interacting with the app, React occasionally shows stale or swapped content. Identify the line that contains the bug.#

import React from 'react';

function FruitList({ fruits }) {
  return (
    <ul>
      {fruits.map((fruit, index) => (
        <li key={index}>
          {fruit}
        </li>
      ))}
    </ul>
  );
}

export default FruitList;
Show answer

The bug is on line 6.

Why:

The bug is on line 6: key={index}. Using the array index as a key is problematic when the list can be reordered, filtered, or have items added/removed at positions other than the end. React uses key to identify which items have changed between renders. When indices shift (e.g., an item is prepended or deleted), React reuses the wrong DOM nodes, causing stale or swapped content. The fix is to use a stable, unique identifier from the data itself (e.g., key={fruit.id} or key={fruit} if values are unique).

A parent component re-renders with unchanged props passed to the child. Which of the following mechanisms, applied on their own, can directly prevent the child component from re-rendering as a result of the parent's re-render? Select all that apply.#

Options

Pick every one that applies.

Show answer

Only React.memo (for function components) and React.PureComponent (for class components) directly prevent a child from re-rendering when its props are unchanged. Both perform a shallow comparison and skip the child's render. useCallback alone, useMemo inside the child, or useReducer in the parent do not gate the child's re-render — they need a memoization boundary on the child itself to have any effect.

Why:

React.memo wraps a function component and shallow-compares props; when they're unchanged React skips rendering the child entirely. React.PureComponent does the equivalent shallow comparison of props and state via a built-in shouldComponentUpdate for class components. Both are React's documented, first-class mechanisms for preventing unnecessary child re-renders. useCallback alone only stabilizes a function reference; without React.memo/PureComponent on the child, the child still re-renders whenever the parent does — reference stability without a bail-out mechanism on the child changes nothing. useMemo inside the child memoizes a value used during rendering; it does not stop the child from being rendered in the first place — by the time the memoized computation is consulted, the child's render function is already executing. useReducer in the parent just manages the parent's state and provides no mechanism to gate child re-renders.

When React's reconciler detects that the element type has changed at the same position in the tree (e.g., <Counter /> replaced by <div>), it follows a specific sequence. Order these steps from first to last as React processes the change:#

Put these in order

Show answer

Detect mismatch → destroy old instance → instantiate and render new component → commit to DOM. When React's reconciler sees that the element type at a tree position has changed, it first identifies the type mismatch, then unmounts and discards the old component (including its state), next creates and renders the new component from scratch, and finally commits the resulting DOM nodes in the commit phase.

Why:

React's reconciliation compares elements by their type. When the type changes at a given position in the tree (e.g., from <Counter /> to <div>), React unmounts the old component and mounts a new one — all local state is destroyed. When type stays the same, React updates the existing instance and preserves state. Here, toggling showInput changes the element at the second position from <Counter /> to <footer> and back. Each toggle unmounts and remounts Counter, resetting its count to 0. The correct ordering of React's reconciliation steps when a type mismatch is detected is: tear down old tree → create new tree → commit to DOM.

Why does React need a key on list items, and what makes a good key?#

Show answer

Keys give each list item a stable identity so React can match elements across renders during reconciliation, preserving their state and minimizing DOM work. A good key is stable and unique among siblings — typically a data id — not the array index when the list can reorder.

Why:

Without stable keys React falls back to index matching, which moves state to the wrong items when the list changes. Keys are about identity, not ordering.

Which of the following statements correctly describe heuristics used by React's reconciliation (diffing) algorithm? Select all that apply.#

Options

Pick every one that applies.

Show answer

The correct heuristics are: differing element types cause a full subtree teardown and rebuild, and the key prop is used to preserve or reset component identity in lists. React does NOT reuse DOM nodes when the component type changes, and the diffing is not a separate pre-pass over the whole tree — React interleaves reconciliation and fiber work before a single commit phase.

Why:

React's reconciliation algorithm (the 'diffing' algorithm) makes several key assumptions to keep complexity at O(n) instead of O(n³). (1) Elements of different types produce entirely different trees — React will tear down the old tree and build a new one rather than trying to patch across types. (2) The developer can hint at stable identity across renders using the key prop; React uses keys to match children in a list. React does NOT diff across sibling positions without keys, and it does NOT perform cross-level tree moves — if a subtree moves to a different depth, React unmounts and remounts it rather than relocating the fiber. The claim ('React reuses DOM nodes when a component type changes if the props are identical') is false, and the claim ('React diffs the full tree depth-first before committing any changes') misrepresents the algorithm — React uses a two-phase approach (render + commit), but the diffing itself is depth-first per fiber, not a separate full-tree pre-pass. The two correct heuristics are differing element types and the key prop.

Consider the following React code:#

Options

Show answer

Child will re-render every time the button is clicked, so the statement is False. Although items is stabilized by useMemo and passes React.memo's shallow comparison, the style prop is an inline object literal ({ color: 'red' }) that creates a new reference on every parent render. React.memo performs referential equality checks (===) on each prop, so the changed style reference causes Child to re-render despite the memo wrapper.

Why:

This question tests understanding of React's fiber bailout mechanism and referential equality. React.memo wraps Child and performs a shallow prop comparison. On the second render triggered by setCount, style is an object literal { color: 'red' } created inline. Even though its shape and values are identical to the previous render's object, it is a new reference each time — so the shallow comparison (===) fails, and Child re-renders. items is defined with useMemo and has no changing dependencies, so it retains the same reference and passes the memo check alone. But because style fails, Child re-renders regardless. The fix would be to also memoize style with useMemo or useCallback. The correct answer is that Child does re-render on every parent render, despite React.memo.

How can changing a component's key be used to reset its state?#

Show answer

React treats an element with a new key as a different instance, so it unmounts the old one (discarding its state) and mounts a fresh one. Giving a component a key that changes (e.g. key={userId}) is a deliberate way to reset all its internal state when that value changes.

Why:

Keys drive identity during reconciliation. A different key at the same position forces a remount, which is the idiomatic state-reset technique instead of syncing props into state via effects.

Consider the following React code:#

Options

Show answer

In React 18, when a key change causes one Profile to unmount and a new one to mount, logExit(1) (the old instance's cleanup) runs before logView(2) (the new instance's effect) within the same asynchronous passive-effects flush. This ordering is consistent in React 18's implementation — cleanups for unmounted components are processed before new mount effects — though it is an implementation detail rather than an explicitly documented API guarantee.

Why:

When a component's key changes, React treats it as an entirely different component identity: the old subtree is unmounted and a fresh one is mounted. useEffect callbacks (both setup and cleanup) are passive effects — they are scheduled asynchronously via React's internal scheduler (using a MessageChannel post-message or similar mechanism) and run after the browser has been given the opportunity to paint, though a visible paint is not strictly guaranteed before the flush fires. Within a single passive-effects flush, React's implementation consistently processes all cleanups for unmounted components before running setup effects for newly mounted components, so logExit(1) precedes logView(2). The correct answer correctly captures both the observed behavior and the important nuance that this cross-instance ordering is an implementation detail of React 18 rather than an explicitly documented specification guarantee. The claim that logView(2) is called first because the new instance's mount effect is enqueued before the old instance's cleanup is processed is incorrect: cleanups for destroyed fiber trees are processed before new mount effects in the same flush, not after. The claim that only logView(2) is called because the key changed and React reuses the existing fiber and skips running the old cleanup entirely is incorrect: a key change always triggers a full unmount/remount, so the cleanup is always invoked. The claim that logExit(1) and logView(2) are both called synchronously during the commit phase, before the browser has had any opportunity to schedule a repaint is incorrect: useEffect is asynchronous and deferred; it is useLayoutEffect that runs synchronously after DOM mutations but before paint.

Sources

The official documentation these questions are checked against:

Related interview questions

Job market

See react salaries and hiring demand from live job postings.

The other 14 questions

This page shows 10 and marks what you pick. That's as far as a page can go. A free account opens the other 14 and keeps every answer. What you miss comes back until it's right: after a day, then at longer gaps.

Start with this topic

Free · the whole bank · 100 marked answers per 30 days · written feedback on the paid plan

Interview booked? Practise the job ad instead

What moved, monthly

One email a month when the bulletin comes out: what moved in the markets we track, and the new question topics we published. Confirm your address to join. Unsubscribe any time.