📘 ReactJS

Event Handling and Forms

useCallback and React.memo are performance optimization tools. They are commonly used together when a parent component renders frequently and a child component can avoid unnecessary work when its inputs have not changed.

S

Site Administrator

📅 Sep 27, 2026 🕒 5 min read 👁 31 views
☆ Save 𝕏 in f ✆
Event Handling and Forms

useCallback and React.memo are performance optimization tools. They are commonly used together when a parent component renders frequently and a child component can avoid unnecessary work when its inputs have not changed.

10.1 What Problem Are They Solving?

When a component renders, JavaScript creates new function values for functions declared during that render. If such a function is passed to a memoized child, the child can see a new function reference even when the function's behavior has not meaningfully changed.

useCallback can preserve the function reference between renders when its dependencies have not changed. React.memo can skip a child render when its props are considered unchanged.

10.2 React.memo

React.memo creates a memoized component. When its parent renders, React can skip rendering the memoized child if its props have not changed according to the comparison used by the memoized component.

const UserCard = React.memo(function UserCard({ name }) {
    console.log("UserCard rendered");

    return <div>{name}</div>;
});

Memoization is an optimization. It should not be required for the component to be logically correct.

10.3 Why Function Props Can Break Memoization

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

    function handleSelect() {
        console.log("Selected");
    }

    return (
        <>
            <button onClick={() => setCount(count + 1)}>
                {count}
            </button>

            <Child onSelect={handleSelect} />
        </>
    );
}

On each parent render, handleSelect is a new function object. If Child is memoized, its function prop can therefore appear changed even when the logic is equivalent.

10.4 useCallback

useCallback caches a function definition between renders until one of its dependencies changes.

const handleSelect = useCallback(() => {
    console.log("Selected");
}, []);

Now the function reference can remain stable across renders while the dependency list remains unchanged.

10.5 useCallback + React.memo

const Child = React.memo(function Child({ onSelect }) {
    console.log("Child rendered");

    return (
        <button onClick={onSelect}>
            Select
        </button>
    );
});

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

    const handleSelect = useCallback(() => {
        console.log("Selected");
    }, []);

    return (
        <>
            <button onClick={() => setCount(count + 1)}>
                Count: {count}
            </button>

            <Child onSelect={handleSelect} />
        </>
    );
}

When the parent count changes, the parent renders again. Because handleSelect retains its reference and Child's other props remain unchanged, the memoized Child may be able to skip its render.

10.6 Performance Flow

flowchart TD
A[Parent State Changes] --> B[Parent Renders]
B --> C{Child Props Changed?}
C -->|No| D[React.memo Can Skip Child Render]
C -->|Yes| E[Child Renders]
B --> F[useCallback Checks Dependencies]
F --> G[Stable Function Reference If Dependencies Unchanged]

10.7 Dependency Changes

If a callback depends on a value, that value belongs in the dependency list.

const handleSelect = useCallback(() => {
    console.log(userId);
}, [userId]);

When userId changes, React can create the callback for the new dependency value.

10.8 Functional Updates Can Reduce Dependencies

Sometimes a callback can use a functional state update instead of reading the current state value directly.

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

This callback does not need the current count value because React provides the previous state to the updater.

10.9 React.memo Is Not Deep Comparison

Memoized components generally rely on comparison of prop values using shallow/reference equality semantics. A new object or function reference can therefore be considered changed even if its contents look identical.

const options = { pageSize: 20 };

<Child options={options} />

If options is recreated on every parent render, the child receives a new object reference. Depending on the design, stable values can be created outside the component or memoized appropriately.

10.10 When Not to Use useCallback

Adding useCallback everywhere can make code more complex without producing a meaningful performance improvement. It is most useful when function identity matters, for example when passing a callback to a memoized child or when a callback is a dependency of another Hook and stable identity is useful.

10.11 When Not to Use React.memo

If a component is inexpensive to render or its props change frequently, memoization may provide little benefit. A component should not be wrapped with React.memo automatically simply because performance is important.

10.12 useCallback vs useMemo

ConceptuseCallbackuseMemo
What is cached?Function referenceCalculation result
Typical purposeStable callback identityAvoid repeated expensive calculation
ReturnsFunctionCalculated value
Common pairingReact.memoMemoized derived data

10.13 React.memo vs useCallback

ToolOptimization Target
React.memoComponent rendering based on props.
useCallbackFunction reference identity.
useMemoCalculated value identity/result.

10.14 Common Mistakes

  • Assuming React.memo prevents every child render.
  • Using useCallback for every function without a performance reason.
  • Leaving dependencies out of useCallback.
  • Forgetting that new object and array references can also cause memoized children to render.
  • Thinking memoization changes application behavior rather than optimizing it.
  • Optimizing before identifying an actual rendering or calculation bottleneck.

10.15 Interview Questions

  1. What is React.memo?
  2. What problem does useCallback solve?
  3. Why can a normal function prop cause a memoized child to render?
  4. How do useCallback and React.memo work together?
  5. What happens when a callback dependency changes?
  6. What is the difference between useCallback and useMemo?
  7. Does React.memo perform a deep comparison of every prop?
  8. Can useCallback make performance worse?
  9. When should you avoid memoization?
  10. How can functional state updates reduce callback dependencies?

10.16 Key Takeaways

  • React.memo can skip rendering a component when its props have not changed.
  • useCallback can keep a callback reference stable between renders.
  • They are often useful together when function props are passed to memoized children.
  • Dependencies must accurately represent values used by callbacks.
  • Memoization is an optimization, not a correctness requirement.
  • Use profiling and actual performance needs to guide optimization.

Conclusion

useCallback and React.memo are easiest to understand when you focus on reference identity. React.memo optimizes component rendering based on props, while useCallback can stabilize a function prop. Used appropriately, they can reduce unnecessary work; used everywhere without a reason, they can add complexity without meaningful benefit.

Comments & Ratings (0)

Log in or create a student account to comment and rate this article.

Be the first to comment on this article.

Never miss a new post 📬

Get an email whenever a new article, project, cheatsheet or video drops.

✅

ℹ️