← Back to Chapters

useMemo() and useCallback()

⚛️ useMemo() & useCallback()

? Quick Overview

useMemo() and useCallback() are React performance hooks that help avoid unnecessary work during re-renders by memoizing values and functions.

? Key Concepts

 

  • useMemo() memoizes computed values
  • useCallback() memoizes function references
  • Both rely on dependency arrays
  • Useful for optimizing expensive or repeated operations

⚛️ Introduction

Both useMemo() and useCallback() are React hooks that help improve performance by memoizing values or functions between renders.

- useMemo() caches the result of a computation
- useCallback() caches the function itself

? useMemo() — Caching Computed Values

useMemo() prevents expensive calculations from running on every render. It only recomputes when dependencies change.

? View Code Example
// useMemo prevents expensive factorial calculation on every render
import React, { useMemo, useState } from "react";

function FactorialCalculator() {
const [num, setNum] = useState(5);
const [count, setCount] = useState(0);

const factorial = useMemo(() => {
console.log("Calculating factorial...");
let result = 1;
for (let i = 1; i <= num; i++) result *= i;
return result;
}, [num]);

return (
<div>
<h4>Factorial of {num}: {factorial}</h4>
<input
type="number"
value={num}
onChange={(e) => setNum(Number(e.target.value))}
/>
<button onClick={() => setCount(count + 1)}>
Re-render ({count})
</button>
</div>
);
}

export default FactorialCalculator;

The factorial function runs only when num changes, not when the button triggers a re-render.

? useCallback() — Caching Functions

In React, functions are recreated on every render. useCallback() keeps the same function reference unless its dependencies change — crucial for preventing child re-renders.

? View Code Example
// useCallback stabilizes function reference passed to child
import React, { useState, useCallback } from "react";
import Child from "./Child";

function Parent() {
const [count, setCount] = useState(0);

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

return (
<div>
<h4>Count: {count}</h4>
<Child onClick={increment} />
</div>
);
}

export default Parent;

// Child.js
import React from "react";

function Child({ onClick }) {
console.log("Child rendered");
return <button onClick={onClick}>Increment</button>;
}

export default React.memo(Child);

Without useCallback(), increment would be recreated each render, causing the memoized child to re-render.

⚙️ useMemo vs useCallback

  • useMemo(): Memoizes computed values and returns cached results
  • useCallback(): Memoizes functions and returns stable references
  • Both depend on dependency arrays

? When to Use Them

  • When expensive calculations make re-renders slow → use useMemo()
  • When child components re-render due to function prop changes → use useCallback()
  • When optimizing without measuring → don’t use

Always profile before applying memoization — unnecessary caching can waste memory.

? Interactive Concept Diagram

Render Flow:

  • State Change → Component Render
  • useMemo() checks dependency changes
  • useCallback() preserves function identity
  • Child components skip unnecessary renders

? Live Simulator

Test how Dependency changes vs. Unrelated updates affect the result.

Factorial: 120
Change inputs above...

? Tips & Best Practices

  • Combine useCallback() with React.memo()
  • Keep dependency arrays accurate
  • Avoid wrapping every function unnecessarily
  • Use useMemo() for derived data, not constants

? Try It Yourself

  1. Implement a factorial calculator using useMemo()
  2. Stabilize callback props using useCallback()
  3. Remove hooks and observe console logs
  4. Profile renders using React DevTools

Goal: Understand how memoization reduces redundant renders and improves performance.