DEV Community

Cover image for Memoization in React: Or How I Thought I Optimized My App (But Mostly Just Felt Productive)
Boluwatife Adewusi
Boluwatife Adewusi

Posted on

Memoization in React: Or How I Thought I Optimized My App (But Mostly Just Felt Productive)

If you’ve been writing React for a while, there’s a phase you inevitably enter.

It’s the “performance phase.”

This is where you stop worrying about getting things to work and start worrying about getting things to work fast. You start side-eyeing re-renders like they owe you money. You open React DevTools more than you open Slack. And at some point, you Google:

“How to prevent re-renders in React”

And React, in its infinite wisdom, responds with three magical words:

  • useMemo
  • useCallback
  • memo

You read a few blog posts. You watch a YouTube video at 1.25x speed. You sprinkle some memoization into your code like seasoning.

Optimized.

Or… so you think.

That was me. For a long time.

I felt like I was writing performant React. But recently, I decided to stop trusting vibes and actually observe how React behaves in a few scenarios.

What I found was… humbling.

Turns out, I had been “optimizing” my app in ways that made me feel productive but didn’t actually do what I thought they did.

So today, I want to walk you through some not-so-obvious misconceptions about memoization in React, using this repo as our playground:

👉 Repo: https://github.com/bolusarz/react-memo-app

And yes, this is me bringing you along on my learning journey. If you disagree with anything—or if something clicks for you—please yell (politely) in the comments.


Before We Get Fancy, Let’s Agree on Some Facts

A React component re-renders when:

  1. Its internal state changes
  2. Its parent re-renders

Some people add a third one:

  1. When its props change

Personally, I think #2 already covers that. If you disagree, feel free to fight me in the comments. I’m open. 😄

Keep these two rules in mind—we’ll keep coming back to them like a lecturer pointing at the same slide over and over saying “this will be on the exam.”


Misconception #1

“Passing memoized values into a component prevents re-renders”

Short answer: Nope.

Long answer: Let me show you why I fell for this too.

Switch to the without-memoized-component branch in the repo. You’ll see two components:

memoized-component.tsx

memoized-component.tsx code content
(pretend I’m dramatically pointing at it)

App.tsx

app.tsx code content
(nod thoughtfully)

Notice something important in App.tsx:

We’re using useCallback before passing a function down as a prop.

At this point, past-me was already celebrating.

“The function is memoized. React won’t re-render the child. I am a performance genius.”

Now click the count button.

Rerender mess

The child component re-renders every single time.

“But wait,” you say, adjusting your glasses,

“the function isn’t changing!”

Correct. Gold star ⭐

The function reference is stable.

But remember the rules.

Go back. Look at rule #2.

A component re-renders when its parent re-renders.

The parent’s state changed.

The parent re-rendered.

So the child re-rendered.

useCallback didn’t fail you.

Your expectations did. (Mine too.)

In this scenario, useCallback is basically emotional support—it makes you feel better but doesn’t actually stop anything.

“So… how do we fix it?”

Easy.

Wrap the child component with memo.

Now refresh the app (yes, actually refresh it, go on).

Click the button again.

Rerender solved

No re-render.

Now we’ve achieved what we thought we had achieved earlier.

The lesson here:

Memoizing props without memoizing the component does absolutely nothing for re-renders.


Misconception #2

“If I memoize a component, I’m safe”

Ah yes. The other side of the trap.

memo only prevents re-renders when props don’t change.

And React checks this using shallow comparison.

So if you do this:

  • Pass an inline function
  • Pass a freshly created object
  • Pass a derived value that isn’t memoized

React sees:

“New reference? Cool. Re-render.”

At that point, your memo wrapper is just decorative.

You can test this yourself:

  • Remove useCallback from App.tsx
  • Click the button
  • Watch the render count climb like it’s training for cardio

The painful truth

Memoizing a component without memoizing the values you pass into it is like locking your front door and leaving the windows wide open.

Looks secure. Isn’t.


So… Should We Memoize Everything?

Please don’t.

That’s not optimization, that’s a future bug report waiting to happen.

Memoization has:

  • A mental cost
  • A maintenance cost
  • And sometimes even a performance cost

It shines only when:

  • Re-renders are expensive
  • Props are stable
  • You’ve measured a real problem (not just a feeling)

I’ll dive deeper into when memoization actually makes sense in another article.


Final Thoughts (From Someone Who Learned the Hard Way)

For a long time, I thought I was writing performant React because I was using the right tools.

What I wasn’t doing was:

  • Observing behavior
  • Questioning assumptions
  • Understanding why React was re-rendering

Memoization isn’t magic.

It’s just a tool.

And like all tools, it works best when you actually know what it does.

If I got anything wrong, misunderstood something, or if this post helped you see memoization differently, drop a comment. I’d genuinely love to hear your thoughts.

See you in the next one 👋

Top comments (0)