React.memo, useMemo, useCallback — Step-by-Step
🧠 Why Use These?
React re-renders components whenever state or props change. But sometimes:
- You don’t want a child to re-render if props didn’t change.
- You want to avoid recalculating expensive functions.
That’s where these tools come in.
✅ 1. React.memo
– Memoize Components
📌 What it does:
Wrap a component to prevent it from re-rendering unless props actually change.
🧾 Example:
import React from "react";
const Child = React.memo(({ name }) => {
console.log("👶 Child rendered");
return <p>Child Name: {name}</p>;
});
export default Child;
Use in Parent:
import React, { useState } from "react";
import Child from "./Child";
function Parent() {
const [count, setCount] = useState(0);
return (
<>
<h2>Count: {count}</h2>
<button onClick={() => setCount(count + 1)}>Increase Count</button>
<Child name="Alice" />
</>
);
}
export default Parent;
🧠 Output:
- Even if
count
changes,Child
won’t re-render unlessname
prop changes.
✅ 2. useMemo
– Memoize Expensive Values
📌 What it does:
Only re-computes a value when dependencies change.
🧾 Example:
import React, { useState, useMemo } from "react";
function ExpensiveCounter() {
const [count, setCount] = useState(0);
const [dark, setDark] = useState(false);
const slowFunction = (num) => {
console.log("⚙️ Slow calculation...");
for (let i = 0; i < 1000000000; i++) {} // fake delay
return num * 2;
};
const doubleCount = useMemo(() => slowFunction(count), [count]);
const themeStyles = {
backgroundColor: dark ? "black" : "white",
color: dark ? "white" : "black",
padding: "20px",
marginTop: "10px"
};
return (
<>
<button onClick={() => setCount((c) => c + 1)}>➕ Increment</button>
<button onClick={() => setDark((d) => !d)}>🌓 Toggle Theme</button>
<div style={themeStyles}>
<h2>Double: {doubleCount}</h2>
</div>
</>
);
}
export default ExpensiveCounter;
🧠 Without useMemo
:
Toggling theme will re-run slowFunction
unnecessarily.
With useMemo
, it only runs when count
changes.
✅ 3. useCallback
– Memoize Functions
📌 What it does:
Returns the same function instance unless dependencies change.
🧾 Example:
import React, { useState, useCallback } from "react";
import List from "./List";
function App() {
const [number, setNumber] = useState(1);
const [dark, setDark] = useState(false);
const getItems = useCallback(() => {
return [number, number + 1, number + 2];
}, [number]);
const theme = {
backgroundColor: dark ? "#333" : "#eee",
color: dark ? "#eee" : "#333",
padding: "20px"
};
return (
<div style={theme}>
<h1>useCallback Example</h1>
<button onClick={() => setNumber((n) => n + 1)}>➕</button>
<button onClick={() => setDark((d) => !d)}>🌗</button>
<List getItems={getItems} />
</div>
);
}
📂 List.js
import React, { useEffect, useState } from "react";
function List({ getItems }) {
const [items, setItems] = useState([]);
useEffect(() => {
console.log("📦 getItems changed");
setItems(getItems());
}, [getItems]);
return items.map((item) => <div key={item}>{item}</div>);
}
export default List;
Without useCallback
, getItems()
is recreated every render and triggers useEffect
unnecessarily.
purpose, differences, and when to use each one
🧠 Summary Table
Feature | What it does | Used for | Returns | Common Use Case |
---|---|---|---|---|
React.memo | Memoizes a component | Avoids re-render | Component | Prevent child component re-render if props same |
useMemo | Memoizes a value (result) | Expensive calc | Value (e.g., number, array) | Avoid recalculating unless dependencies change |
useCallback | Memoizes a function | Stable function | Function | Prevents passing new function on every render |
✅ 1. React.memo(Component)
📌 Wraps a functional component and prevents re-render if props haven’t changed.
const MyComponent = React.memo(function MyComponent({ name }) {
return <h2>{name}</h2>;
});
🧠 Use When:
You have a child component receiving unchanged props, but it re-renders anyway due to parent changes.
✅ 2. useMemo(() => compute(), [deps])
📌 Caches a computed value, and only recalculates it if its dependencies change.
const expensiveValue = useMemo(() => slowFunction(input), [input]);
🧠 Use When:
- You’re doing a slow/expensive calculation
- You want to avoid recalculating on every render
✅ 3. useCallback(() => fn, [deps])
📌 Caches a function so its reference doesn’t change unless dependencies change.
const handleClick = useCallback(() => {
doSomething();
}, [dependency]);
🧠 Use When:
- You pass a function to a child component (especially
React.memo
-wrapped) - You want to prevent useEffect in the child from running again
🧪 Visual Flow
Parent Re-renders ➜
├─ Child with new props/function ➜ child re-renders
├─ React.memo() + same props ➜ no re-render
├─ useMemo() ➜ reuses previous value
└─ useCallback() ➜ reuses previous function
Keep Learning 🙂