A Mental Model for React Rendering That Actually Sticks
Stop guessing why your component re-rendered. A clear, durable model of how React decides what to render and when — and what that means for performance.
Most React performance confusion comes from a fuzzy mental model of when
components render. Once the model is crisp, the optimizations become obvious —
and you stop reaching for memo everywhere out of superstition.
Rendering is just calling your function
A “render” is React calling your component function to get a description of the UI. It does not necessarily touch the DOM. React renders, diffs the result against the previous tree, and only then commits the minimal DOM changes.
So the cost of a render is: your function body + reconciliation, not repaint the screen.
What triggers a render?
A component re-renders when:
- Its state changes (
useState,useReducer). - Its parent re-renders (by default, children re-render too).
- A context it consumes changes.
That second point surprises people. By default, when a parent renders, all of its children render, regardless of whether their props changed.
function Parent() {
const [count, setCount] = useState(0);
return (
<div>
<button onClick={() => setCount((c) => c + 1)}>{count}</button>
<ExpensiveList /> {/* re-renders on every click — even with no props */}
</div>
);
}
The three levers
When a re-render is genuinely expensive, you have three tools:
React.memo— skip a child’s render if its props are shallow-equal.useMemo— cache an expensive computed value between renders.useCallback— keep a function identity stable somemochildren don’t break.
Reach for these only after you’ve measured a real cost. Premature memoization adds complexity and can even be slower than the render it’s avoiding.
Composition beats memoization
Often the cleanest fix isn’t memo at all — it’s moving state down or passing
children as props so they don’t re-render:
function Parent({ children }: { children: React.ReactNode }) {
const [count, setCount] = useState(0);
return (
<div>
<button onClick={() => setCount((c) => c + 1)}>{count}</button>
{children} {/* created by the grandparent — does NOT re-render here */}
</div>
);
}
Internalize this: state changes render a component and its subtree; props
identity decides whether memo’d children opt out. With that model, React
performance stops being mysterious.
Related articles

Building a Full SaaS Application with NestJS, React, PostgreSQL and Docker
A step-by-step, production-grade guide: architecture, multi-tenant database design, JWT auth, NestJS APIs, a React frontend, Docker, CI/CD with GitHub Actions, scalability, and the best practices that hold up in production.

MCP Servers Explained: The Future of AI Tool Integration
What the Model Context Protocol (MCP) is, how MCP servers work, why it beats bespoke API glue, a hands-on server example, the growing ecosystem, security considerations, and where it's all heading.

Why AI Coding Agents Will Change Software Development in 2026
What AI coding agents are, how they differ from autocomplete assistants, the tools that matter in 2026, real use cases, the productivity math, security risks, and how to fold agents into your daily workflow without regrets.
Have a project or an idea?
We don't just write about software — we build it. Tell us what you're working on and we'll get back within 1–2 business days.