React | React.memo, useMemo, useCallback – what’s the difference?

I always mix these up, so I finally sat down to write a quick comparison. They’re all about React performance optimisation, but they solve slightly different problems.
1. React.memo – don’t rerender this if props are the same
tsx
const Child = React.memo(({ name }: { name: string }) => {
console.log('Child rendered');
return <div>Hello, {name}</div>;
});
const Parent = () => {
const [count, setCount] = useState(0);
return (
<>
<button onClick={() => setCount(count + 1)}>Click</button>
<Child name="Miyeon" />
</>
);
};
If you click the button, Parent rerenders – but Child won’t, because its prop name hasn’t changed. ✌️
2. useMemo – cache a heavy calculation
tsx
const ExpensiveCalc = ({ num }: { num: number }) => {
const result = useMemo(() => {
console.log('Heavy calculation...');
let total = 0;
for (let i = 0; i < 100_000_000; i++) total += i;
return total + num;
}, [num]);
return <div>Result: {result}</div>;
};
Without useMemo, this would re-run the whole loop every time the component renders – even if num is the same. That’s a nope.
3. useCallback – keep a function reference stable
tsx
const Parent = () => {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
console.log('Clicked!');
}, []);
return (
<>
<button onClick={() => setCount(count + 1)}>Increase</button>
<Child onClick={handleClick} />
</>
);
};
const Child = React.memo(({ onClick }: { onClick: () => void }) => {
console.log('Child rendered');
return <button onClick={onClick}>Child Button</button>;
});
If you define handleClick inline without useCallback, it creates a new function on every render – which means Child thinks the props changed and rerenders. 🫠
✅ So when do I actually use these?
Honestly? I mostly reach for them when I see real performance issues. Premature optimisation is a rabbit hole. But if:
- My component rerenders too much → try React.memo
- A slow calculation keeps running → try useMemo
- I’m passing functions down and memoised children keep rerendering → try useCallback
🚀 Hope this makes things a bit clearer for someone else on the same journey.
Subscribe to my newsletter
Read articles from Valencia Miyeon Jang directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Valencia Miyeon Jang
Valencia Miyeon Jang
Front-end developer with a background in Korean language QA and education.Experienced in localisation testing, cross-functional teamwork, and user-focused development.I enjoy crafting intuitive web experiences with React, Next.js, and TypeScript — always learning, always building.