Learn UseCallback, useRef & useMemo


🚀 Unlocking React Superpowers: useCallback
, useRef
, and useMemo
— Explained Like You're 5 (Almost)
Let’s be real: hooks like useCallback
, useMemo
, and useRef
can feel like React’s secret spells — powerful, but confusing if you don’t know when or how to cast them.
In this post, we’ll demystify these hooks, explain when to use them (and when not to), and show you how they help your app stay fast, clean, and smart.
🧠 useCallback
: The Memory Saver for Functions
🤔 What’s the Problem?
Every time a component re-renders, all its inner functions are reborn. Yes, even that innocent little arrow function you wrote inside the component. And here’s the kicker: if you’re passing those functions to child components, React will think they’ve changed—even if the logic is the same!
This can lead to unnecessary re-renders, especially if you're using React.memo()
in child components. That's wasted work. And nobody likes wasted work.
🛠️ The Fix: useCallback
useCallback
tells React:
“Hey, if these dependencies haven’t changed, don’t bother creating a new version of this function. Just reuse the last one.”
🧪 Example
const handleClick = useCallback(() => {
console.log("Button clicked!");
}, []);
Now handleClick
will stay exactly the same across renders — unless you change its dependencies.
✅ When to Use
Passing stable functions to
React.memo()
childrenDebouncing or throttling callbacks
Avoiding infinite loops in
useEffect
🪄 useRef
: Your Secret Pocket for Storing Things
🧠 What Is It?
Imagine a little box attached to your component that you can put things into — and they stay there forever (well, for the life of the component).
That’s useRef
.
Unlike useState
, updating a ref
doesn’t cause a re-render. It just quietly holds onto values behind the scenes.
💡 Popular Uses
DOM Access:
const inputRef = useRef(null); inputRef.current.focus();
Timers and Intervals
Keeping values alive between renders (like the previous value of a prop)
🔥 Bonus
The object returned by useRef()
is stable. It never changes between renders — perfect for keeping track of things without triggering React’s attention.
🧮 useMemo
: Stop Recalculating the Obvious
🧠 What’s Going On?
Imagine calculating the square root of 5000 numbers every time your component renders. Not ideal, right?
That’s what React does unless you tell it not to. useMemo
helps you remember expensive calculations, so React doesn’t redo them unless it truly has to.
📦 The Memoized Value
const expensiveResult = useMemo(() => {
return heavyComputation(input);
}, [input]);
React runs the function once — and only re-runs it if input
changes. That’s performance magic right there.
✅ When to Use
Expensive loops, filters, or calculations
Derived values from state/props
Preventing unnecessary re-renders in deeply nested components
🥊 useCallback
vs. useMemo
: What’s the Difference?
This is the big one! Let’s clear the confusion once and for all.
Concept | useCallback | useMemo |
It remembers… | A function | A value |
Returns a… | Memoized function | Memoized value |
You use it for | Keeping function references stable | Avoiding re-computation of heavy logic |
Real-world use | Click handlers, API triggers | Filtered lists, derived state |
👉 Think of useCallback(fn)
as useMemo(() => fn)
. Technically, it’s the same behavior — just focused on functions, not results.
🤯 Putting It All Together: A Practical Combo
const SearchBox = ({ query }) => {
const inputRef = useRef();
const [results, setResults] = useState([]);
const fetchResults = useCallback(() => {
fetch(`/api/search?q=${query}`)
.then(res => res.json())
.then(setResults);
}, [query]);
const filtered = useMemo(() => {
return results.filter(item => item.active);
}, [results]);
useEffect(() => {
fetchResults();
}, [fetchResults]);
return (
<div>
<input ref={inputRef} placeholder="Search..." />
<ul>
{filtered.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</div>
);
};
Here’s what’s happening:
useRef
grabs the DOM input (no re-render).useCallback
ensures the fetch function doesn’t get recreated every render.useMemo
avoids filtering the same list over and over again.
Result: Smarter code, fewer renders, faster UI.
🧨 Common Pitfalls
Overusing these hooks
Don’t optimize for the sake of it. Only use them if you see performance issues or unstable references.Empty dependency arrays where they shouldn’t be
If you freeze a value that should update (but don’t include its dependencies), things break.Expecting
useRef
to re-render things
Nope. If you want reactivity, useuseState
.
✨ Final Thoughts
React hooks are like tools in a toolbox — and useCallback
, useMemo
, and useRef
are some of the sharpest ones. But like any sharp tool, you only use them when they solve a real problem.
Don’t memorize these hooks — understand them.
And now that you do, your React code is going to be faster, cleaner, and way more optimized.
Subscribe to my newsletter
Read articles from Jayant Verma directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
