Memoized

useCallback

const fn = useCallback(() => , [deps])

Caches a function definition between re-renders. Essential for optimizing performance and preventing unnecessary child updates.

Memoization

useCallback is a hook that lets you cache a function definition between re-renders. It's a key tool for performance optimization in React.

The "New Function" Problem

In JavaScript, functions are objects. A function defined inside a component is re-created on *every single render*. This breaks referential equality checks.

Stable References

By wrapping your function in useCallback, React gives you the *same exact function instance* across renders, unless its dependencies change.

Visual Proof

Try it yourself. When enabled, typing in the parent input won't trigger re-renders in the memoized child, because the callback reference stays stable.

The Common Mistake

Passing an inline function to a memoized child component defeats the purpose of React.memo.

ParentComponent.tsx
import { useState, memo } from 'react';

// Child is memoized, but it won't help!
const Child = memo(({ onClick }) => {
  console.log("Child render"); 
  return <button onClick={onClick}>Click me</button>;
});

function Parent() {
  const [text, setText] = useState("");

  // 🔴 PROBLEM: This function is re-created every render.
  // So 'onClick' prop is always "new".
  const handleClick = () => {
    console.log("Clicked");
  };

  return (
    <>
      <input value={text} onChange={e => setText(e.target.value)} />
      <Child onClick={handleClick} />
    </>
  );
}
Inline functions break memoization

The Solution

Wrap the handler in useCallback. Now the function reference is stable, and the child can skip re-rendering.

OptimizedParent.tsx
import { useState, useCallback, memo } from 'react';

const Child = memo(({ onClick }) => {
  console.log("Child render - Optimized!"); 
  return <button onClick={onClick}>Click me</button>;
});

function Parent() {
  const [text, setText] = useState("");

  // ✅ SOLUTION: Stable reference across renders
  const handleClick = useCallback(() => {
    console.log("Clicked");
  }, []); // No dependencies, never changes!

  return (
    <>
      <input value={text} onChange={e => setText(e.target.value)} />
      <Child onClick={handleClick} />
    </>
  );
}
Optimization with useCallback
AlgoAnimator: Interactive Data Structures