Lesson 34 +10 XP

Memoizing Functions with useCallback

Memoizing Functions with useCallback

In JavaScript, functions are first-class objects. Every time a functional component renders, any inline functions defined inside it are re-created as brand new function instances in memory.

function Parent() {
  // Brand new function created in memory on EVERY render of Parent!
  const handleClick = () => console.log("Clicked");

  return <ReactMemoChild onClick={handleClick} />;
}

Because handleClick gets a new memory reference on every render, passing it to a React.memo child component causes shallow comparison to fail, forcing the child to re-render unnecessarily.

What is useCallback?

The useCallback hook caches (memoizes) a function instance between renders. It returns the exact same function memory reference until its dependencies change.

import { useState, useCallback } from 'react';
import React from 'react';

const ChildButton = React.memo(function ChildButton({ onClick, label }) {
  console.log("ChildButton " + label + " rendered");
  return <button onClick={onClick}>{label}</button>;
});

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

  // useCallback maintains identical function reference across renders
  const handleChildClick = useCallback(() => {
    console.log("Child button clicked!");
  }, []); // Empty deps = stable function reference forever

  return (
    <div>
      <p>Parent count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment Parent</button>
      
      {/* ChildButton will NOT re-render when parent count changes! */}
      <ChildButton onClick={handleChildClick} label="Submit" />
    </div>
  );
}

useCallback vs useMemo

  • useMemo(() => fn, deps): Caches the return value of executing fn().
  • useCallback(fn, deps): Caches the function instance fn itself.
// These two lines are functionally identical:
useCallback(fn, deps);
useMemo(() => fn, deps);

Summary & TL;DR

  • Components re-create local function instances on every render.
  • useCallback(fn, [deps]) maintains a stable function memory reference across renders.
  • Essential when passing callback functions as props to memoized child components (React.memo).