Faster React: Memoization with React.memo, useMemo, and useCallback

Optimize re-renders with memoization to speed up heavy components. Great for lists, charts, and large data tables. Avoid premature optimization—profile before applying.

React re-renders components whenever their parent re-renders, even if the props don’t change.
👉 This can cause performance issues in large apps.

Memoization means: “Remember the result of a function until its inputs change.”

  • React.memo → Memoizes components (UI rendering).
  • useMemo → Memoizes values.
  • useCallback → Memoizes functions.

Basics & Need

  • Avoid unnecessary re-renders.
  • Improve performance for expensive calculations.
  • Keep child components lightweight when parent updates frequently.

How to Achieve It

Using React.memo

const Child = React.memo(({ name }) => {
console.log("Rendered:", name);
return <div>Hello {name}</div>;
});

const Parent = () => {
const [count, setCount] = React.useState(0);
return (
<>
<button onClick={() => setCount(count + 1)}>Increase</button>
<Child name="Murli" />
</>
);
};

👉 Child won’t re-render when count changes, because name prop is the same.


Using useMemo (Memoize a Value)

const ExpensiveCalculation = ({ num }) => {
const result = React.useMemo(() => {
console.log("Calculating...");
return num * 2; // Imagine heavy calculation
}, [num]);

return <p>Result: {result}</p>;
};


Using useCallback (Memoize a Function)

const Button = React.memo(({ onClick }) => {
console.log("Button Rendered");
return <button onClick={onClick}>Click</button>;
});

const Parent = () => {
const [count, setCount] = React.useState(0);

const increment = React.useCallback(() => {
setCount((c) => c + 1);
}, []);

return <Button onClick={increment} />;
};

👉 Without useCallback, a new function would be created each render → forcing Button to re-render.

Best Practices

  • Use memoization only when needed (not everywhere).
  • Use React.memo for pure components (same props = same output).
  • Use useMemo for heavy computations.
  • Use useCallback when passing callbacks to memoized children.

Real-World Examples

  1. E-commerce Product List → Product cards memoized to avoid re-render on cart updates.
  2. Dashboard with Charts → Expensive data transformations wrapped in useMemo.
  3. Forms → Memoize field components so typing in one field doesn’t re-render all.

Advantages

  • Faster apps (less unnecessary rendering).
  • Keeps UI responsive under heavy load.
  • Works well with large data sets and complex UI trees.

Disadvantages

  • Premature optimization can complicate code.
  • Memoization itself consumes memory.
  • Can confuse juniors (debugging memoized components is tricky).

Common Problems / Pitfalls

  • Wrapping every component in React.memo → harms performance instead of helping.
  • Forgetting dependency arrays in useMemo / useCallback → stale or wrong data.
  • Overusing memoization on lightweight components → unnecessary complexity.

Summary Recommendation

Use memoization when:

  • A component re-renders often with the same props.
  • You have expensive computations.
  • Passing functions to child components that don’t need to change.

👉 Avoid overuse — always profile before optimizing.