Skip to content
RungsySign in

The Rendering Model

Render, reconcile, commit — the mental model that makes performance work predictable.

45 minDifficulty 3/5react · performanceAI-writtenWritten by a model on 16 August 2026 and not yet read by a person. Checked automatically: schema, the pedagogical rules the hand-written material is held to, and every diagram parsed for real.

Before this

Why this exists

"Re-render" gets used to mean three different things — calling the component function, comparing the result to last time, and actually touching the real DOM — and conflating them is why performance advice about React often sounds contradictory. Render, reconcile, and commit are three distinct phases, and only the last one is expensive.

The mental model

Render is React calling your component function to get a description of what the UI should look like — cheap, pure computation. Reconciliation is React comparing that new description to the previous one to figure out what actually changed. Commit is applying only those specific changes to the real DOM — the genuinely expensive step, because touching the actual browser layout engine costs real time.

How it works

A parent re-rendering re-renders its children by default

When a parent component's state changes and it re-renders, React by default calls every child component function nested inside it too — even children whose own props didn't change at all. This is a deliberate default favouring simplicity over micro-optimisation; it doesn't mean the DOM actually updates for those unaffected children, only that their functions run again.

Reconciliation diffs by type and position, then by key

Comparing the new tree to the old one, React matches elements at the same position with the same type as 'the same element, possibly updated' and reuses the existing DOM node, patching only changed attributes. A different element type at the same position (a `<div>` replaced by a `<span>`) causes React to discard the old DOM node and build a fresh one, losing any internal state that lived there.

Render must be pure — no side effects allowed there

React may call a component function more than once per actual commit (in Strict Mode, deliberately, to help catch bugs) or discard a render's result entirely without committing it (during certain concurrent features). Code that mutates external state directly inside the render body — not in an effect — can run an unexpected number of times or run and then be thrown away, causing genuinely confusing bugs.

The commit phase is where the real cost lives

Calling component functions and diffing objects in memory is fast, even for a moderately large tree. Actually mutating the DOM — which can trigger the browser to recalculate layout and repaint pixels — is comparatively slow. This is why React's diffing exists at all: to minimize how much of that expensive commit work is actually needed, by figuring out the smallest real change first.

The mechanism

A state change triggers React to re-render: it calls the affected component functions (and, by default, their children's functions too) to produce a new element tree. Reconciliation compares this new tree to the previous one, computing the minimal set of real DOM operations required. Only that minimal set is actually applied in the commit phase, after which the browser paints the updated pixels.

flowchart LR
  S[State change] --> R[Render: call component functions]
  R --> Rec[Reconcile: diff new tree vs old]
  Rec --> Com[Commit: apply minimal DOM changes]
  Com --> Paint[Browser paints]
Diagram source for The Rendering Model.

What people get wrong

'Re-render' always means the DOM was updated.
A re-render is a component function being called again to produce a new description — if reconciliation determines nothing actually changed for a given part of the tree, no DOM mutation happens at all for that part, even though the function ran. This confusion is exactly why 'my component keeps re-rendering' isn't automatically a performance problem — the expensive part is the DOM commit, which may not even happen for an unaffected subtree.
React always updates the entire DOM tree from scratch on any state change.
Reconciliation exists specifically to avoid this — it computes a minimal diff and only touches the DOM nodes that actually need to change, reusing existing nodes wherever the type and position match. This misconception leads people to over-optimize by manually avoiding re-renders that were never going to be expensive in the first place, since the DOM diffing was already handling it efficiently.
It's safe to run any code, including mutations, directly in a component's render body.
React may call the render function more than once (Strict Mode) or discard its result without committing (concurrent features), so render must be a pure function of props and state — side effects belong in useEffect, which is guaranteed to run only in sync with actual commits. Code that mutates external state during render can behave unpredictably specifically because of these extra or discarded calls, which is easy to miss in simple testing but shows up as confusing bugs in production.

When not to use it

A child component is expensive to render and its props genuinely don't change often relative to its parent.
`React.memo` on that child skips re-calling its function when its props are shallowly equal to last time — see `react-performance` for when this is actually worth doing.
You need to run code as a genuine side effect of a completed render, like fetching data or subscribing to something.
`useEffect`, which is guaranteed to run only after a render has actually been committed — not during the render function itself, which must stay pure.

Terms

Render phase
React calling component functions to produce a new description of the UI; pure computation with no direct DOM interaction.
Reconciliation
The process of comparing a new render's output tree to the previous one to determine the minimal set of real DOM changes required.
Commit phase
The step where React applies the computed minimal changes to the actual DOM — the comparatively expensive part of an update.
React.memo
A wrapper that skips re-rendering a component when its props are shallowly equal to the previous render's props.

In an interview

If a parent re-renders, do all its children necessarily update the DOM too?

  • by default, all child component functions re-run when a parent re-renders
  • but reconciliation still diffs each child's output against its previous output
  • if a child's rendered output is unchanged, no DOM mutation happens for it, even though its function ran

Can you recall it?

What are the three distinct phases of a React update, and which one is actually expensive?

Keep track of this

Add React Fundamentals to your map and Rungsy will schedule reviews so you actually remember it.