When does React re-render a component, and when does it actually update the DOM?

HighIntermediateReact
Preparing for interviews?

Use guided tracks for structured prep, then practice company-specific question sets when you want targeted interview coverage.

Quick Answer

Explain React’s update pipeline: what a “re-render” really is (re-running component functions to produce a new element tree), what triggers it (state/props/context/parent renders), how reconciliation decides what changed, and why a re-render often results in zero DOM mutations. Include bailouts (Object.is state equality, React.memo/PureComponent), identity pitfalls (inline objects/functions, Context value identity), StrictMode dev behavior, and keys/remount gotchas.

Answer

Core idea

In React, a re-render means: React runs your component again to compute the next React element tree (the in-memory UI description).

Re-render ≠ DOM update. After rendering, React reconciles (matches old vs new trees) and only then commits the minimal DOM mutations if anything actually changed.

Trigger

What happens

Important nuance

State update (useState/useReducer)

Schedules a render for that component

If the new state is Object.is-equal to the old state, React can bail out (no re-render). New object/array references are always “different”.

Parent re-renders

Children are rendered by default

Even if props “look the same”, React will call the child again unless you use React.memo/PureComponent (or a custom comparison).

Prop identity changes

Child re-renders

Inline objects/functions create new references every render → looks like “props changed” to memo/shallow compare.

Context Provider value changes

All consumers may re-render

Context is identity-based too. value={{...}} created inline changes every render unless memoized.

Key / type changes at a position

React remounts the subtree

This is bigger than a re-render: local state resets because React treats it as a different component.

What typically causes re-renders (and the gotchas)

Phase

What React does

Rule of thumb

Render phase

Runs component functions / class render() to compute the next tree

Must be pure (no subscriptions, network calls, DOM writes). React may run it more than once in dev/StrictMode.

Reconciliation

Compares old vs new elements (type + key + position) and decides what to keep/move/mount/unmount

Stable keys/types preserve state and reduce work; unstable identity causes extra work and bugs.

Commit phase

Applies DOM mutations and runs effects/lifecycles

This is when the browser DOM can actually change; effects run after commit.

Render vs reconcile vs commit (the mental model interviewers want)
JSX
import React from 'react';

const Child = React.memo(function Child({ onInc, config }) {
  console.log('Child rendered');
  return <button onClick={onInc}>Inc</button>;
});

export default function Parent() {
  const [count, setCount] = React.useState(0);

  // ❌ NEW function/object every render -> Child sees "new props" -> re-renders
  // const onInc = () => setCount(count + 1);
  // const config = { step: 1 };

  // ✅ Stable identities -> Child can skip renders via React.memo
  const onInc = React.useCallback(() => setCount((c) => c + 1), []);
  const config = React.useMemo(() => ({ step: 1 }), []);

  console.log('Parent rendered');

  return (
    <div>
      <p>Count: {count}</p>
      <Child onInc={onInc} config={config} />
    </div>
  );
}
                  

What this example proves

1) Updating count re-renders Parent.
2) By default, children render too.
3) React.memo lets a child bail out if props are shallow-equal, but only if you keep prop identities stable (callbacks/objects).

Common misconception

Correct framing

“React re-renders the whole app.”

React schedules work for the affected part of the tree. But parent renders do propagate unless you add bailout boundaries (memo) and keep identities stable.

“Virtual DOM diff always computes the minimal edit.”

Reconciliation is heuristic and optimized for common UI patterns. With good keys/types, it’s very efficient; with bad keys/identity churn, it can do extra work.

“If a component re-rendered, the DOM changed.”

Not necessarily. If the computed output is the same (or the changed parts don’t affect the DOM), commit can be a no-op.

“useCallback/useMemo always improves performance.”

They help only when they prevent real work (rerenders of expensive children, expensive computations). Overuse adds complexity and overhead.

Interview-grade corrections to typical statements

Optimization lever

What it actually reduces

Best use

Colocate state (move it down)

The number of components affected by updates

Keep state as close as possible to where it’s used, so fewer parents re-render.

Split components

The size of the rerendered subtree

Separate “fast-changing” parts from “mostly-static” parts.

React.memo / PureComponent

Re-rendering of child components

Pure/presentational children with stable props.

Stable prop identities

False-positive “prop changed” signals

Avoid inline objects/functions when they’re passed to memoized children.

Memoize Context value

Broad consumer rerenders

Wrap provider value creation in useMemo to avoid rerendering all consumers.

Practical ways to reduce unnecessary re-renders (in the order that usually matters most)

Two important gotchas

StrictMode (dev): React may intentionally run render logic more than once to surface unsafe side effects. Don’t treat “double logs” in dev as production behavior.
Keys/type changes: Changing a component’s key or swapping wrappers (e.g., Fragment ↔ div) can cause a remount (state reset), not just a re-render.

Summary

React re-renders when state/props/context might have changed. A re-render is “recompute the next UI tree”, not “mutate the DOM”. React then reconciles and commits only necessary DOM changes. Unnecessary re-renders usually come from unclear state ownership, unstable prop identities (inline objects/functions), broad context updates, or bad keys.

Similar questions
Guides
7 / 41