SyntaxStudy
Sign Up
React useMemo and useCallback for Memoisation
React Beginner 1 min read

useMemo and useCallback for Memoisation

useMemo caches the result of an expensive calculation and only recomputes it when one of its listed dependencies changes. This is valuable when a derived value is computationally heavy — think filtering or sorting a large array — and you want to avoid repeating the work on every render triggered by unrelated state changes. useCallback is essentially useMemo applied to a function. It returns a stable function reference that only changes when its dependencies change. This matters when you pass callbacks down to child components that are wrapped in React.memo, because a new function reference on every render would invalidate the memo and force a re-render even if nothing meaningful changed. Both hooks are optimisations and should not be applied unconditionally. Memoising a cheap calculation adds overhead from the comparison itself. Profile first, then apply these hooks only where you measure a real performance gain.
Example
import { useState, useMemo, useCallback } from 'react';

const numbers = Array.from({ length: 100_000 }, (_, i) => i + 1);

function FilteredList({ threshold }) {
    // Only recomputed when `threshold` changes
    const filtered = useMemo(
        () => numbers.filter(n => n % threshold === 0),
        [threshold]
    );

    return <p>Count: {filtered.length}</p>;
}

// ── useCallback example ────────────────────────────────────────────────────

import React from 'react';

const ExpensiveChild = React.memo(function ExpensiveChild({ onClick }) {
    console.log('ExpensiveChild rendered');
    return <button onClick={onClick}>Click me</button>;
});

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

    // Stable reference – does NOT change when `text` changes
    const handleClick = useCallback(() => {
        setCount(c => c + 1);
    }, []); // no deps – setCount is stable

    return (
        <div>
            <input value={text} onChange={e => setText(e.target.value)} />
            <ExpensiveChild onClick={handleClick} />
            <p>Clicked {count} times</p>
        </div>
    );
}