15/25 lessons60%

When React Re-renders (and Why You Should Care)

React performance isn’t just for the obsessives who measure every frame drop—it’s for anyone who’s ever screamed, “Why is this component re-rendering again?!” Been there. Burned by it. At some point, every React dev gets bitten by unnecessary renders. But most don’t realize that optimizing isn’t about slapping React.memo on everything and praying. It’s about understanding how React thinks. This lesson is your ticket into React’s head. We’ll look at how React re-renders, what triggers it, and why you should care—a lot.

The Re-render Mental Model (a.k.a. React’s Inner Monologue)

React re-renders when state or props change. Sounds simple, right? But here’s the kicker: *it’s not just your component—it’s everything downstream***.

Let me give you a quick breakdown:

If a parent component re-renders, all its children will too, unless they’re memoized or pure. React does a shallow comparison of props. If props.name === props.name, cool. If not, re-render. New function references? New object references? Those are always different* in JavaScript. Which means re-render.

Now, imagine you have this:

javascript
1
2
3
4
5
          function Parent() {
  const user = { name: "Sara" };

  return <Child user={user} />;
}
        

Every time Parent renders, user is a new object—even if the contents are identical. That means Child will re-render too. Ask me how I know this? Because I once had an app where a seemingly innocent onClick={() => doSomething()} in a parent was causing 300+ child re-renders. Nightmare fuel.

The rule of thumb: React re-renders on change—but it can’t always tell what “change” means unless you help it.

🧵 React Fiber and Reconciliation Basics (This Is Not a Marvel Villain)

Here’s what React does under the hood, in human terms.

React uses something called Fiber, its rendering engine. Think of Fiber like a to-do list for React:

Reconciliation = figuring out what changed. Commit Phase = applying those changes to the DOM.

It builds a new virtual DOM tree, compares it to the previous one, then calculates the minimal set of changes. This process is fast, but not free.

Fun fact: Fiber is why React can pause work. It doesn’t have to block your app just to render something. It’s what makes concurrent rendering possible in React 18.

And if you're wondering why key props matter in lists—it’s because React uses them to match old and new elements during reconciliation. No key? React guesses. And React is not a good guesser.

Tracking Re-renders Visually (Because Console.log Ain’t Enough)

You want to see what’s re-rendering?

Install the React Developer Tools extension. Flip over to the “⚛ Profiler” tab. Hit “Record,” then interact with your app.

You'll get a flamegraph showing you which components re-rendered, how long they took, and how many times they re-rendered during an interaction.

Also: add this to any component temporarily if you’re suspicious it’s over-rendering:

javascript
1
2
3
          useEffect(() => {
  console.log("Rendered:", componentName);
});
        

Another old-school trick I use:

javascript
1
          console.count("Child Rendered");
        

It logs every render count—super handy in loops or dropdowns where you swear nothing should change.

Common Causes of Unnecessary Renders (And Why You’ve Probably Done All of Them)

This is where most apps go sideways:

Inline functions like `onClick={() => doSomething()}` recreate a new function every render. New objects/arrays created inside render() are always “different.” Non-memoized child components re-render even if their props didn’t change. Global context changes can cause every consumer to re-render. State updates that don’t actually change values*—React doesn’t skip unless you bail early.

And yeah, I’ve done all of these. Especially the inline functions. I used to think, “It’s just one little function, no big deal.” Then I profiled the app and saw that function nuked performance across 50 child components. Whoops.

Mindset Shift: Optimize with Intent (Don’t Memo All the Things)

Here’s where I get opinionated.

Don’t optimize by default. Optimize because something is slow.

Tools like React.memo, useMemo, and useCallback are powerful—but they add complexity. A wrongly-used useMemo is worse than no optimization at all.

Instead, do this:

Build first, then measure with React DevTools Profiler. Only memoize components that are pure, stable, and called often. * Don’t blindly wrap everything with useCallback just because someone on Twitter said to.

React will re-render. That’s fine. What you care about is how expensive those renders are, not how often they happen.

Next up: we’ll dig into those memoization tools everyone loves to misuse—React.memo, useMemo, and useCallback. Learn when they actually help, and when you’re just wasting CPU cycles: → React.memo, useMemo, useCallback: What, When, Why