Skip to content
intermediatePhase 36 · React

useCallback

Stabilize function references with useCallback for child component optimization.

30m
0 problems
Topic Progress0%

Memoizing Functions

Memoizing Functions

useCallback returns a memoized function that only changes when dependencies change.

Basic Usage

import { useCallback } from "react";

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

  // Without useCallback: new function every render
  const handleClick = () => {
    setCount(count + 1);
  };

  // With useCallback: same function reference
  const handleClick = useCallback(() => {
    setCount((prev) => prev + 1);
  }, []); // No dependencies - function never changes

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={handleClick}>Increment</button>
    </div>
  );
}

With Dependencies

function TodoList({ onAdd }) {
  const [input, setInput] = useState("");

  const handleSubmit = useCallback(
    (e) => {
      e.preventDefault();
      onAdd(input);
      setInput("");
    },
    [input, onAdd] // Re-create when input or onAdd changes
  );

  return (
    <form onSubmit={handleSubmit}>
      <input value={input} onChange={(e) => setInput(e.target.value)} />
      <button type="submit">Add</button>
    </form>
  );
}

Passing to Child Components

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

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

  // Child won't re-render if it uses React.memo
  return <Child onClick={handleClick} />;
}

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

useCallback vs useMemo

useCallback vs useMemo

Key Difference

  • useMemo: Returns a memoized value
  • useCallback: Returns a memoized function

Equivalent Behavior

// These are equivalent:
const memoizedFn = useCallback(() => doSomething(a, b), [a, b]);

const memoizedFn = useMemo(() => () => doSomething(a, b), [a, b]);

When to Use Each

// useMemo for values
const sortedItems = useMemo(
  () => [...items].sort((a, b) => a.name.localeCompare(b.name)),
  [items]
);

// useCallback for functions
const handleSort = useCallback(() => {
  setSortBy((prev) => (prev === "asc" ? "desc" : "asc"));
}, []);

Reference Equality

// Without: new function reference every render
const handleDelete = (id) => {
  setItems((prev) => prev.filter((item) => item.id !== id));
};

// With: same function reference
const handleDelete = useCallback(
  (id) => {
    setItems((prev) => prev.filter((item) => item.id !== id));
  },
  []
);

Practical Example

function DataGrid({ data, onRowClick }) {
  // Memoize expensive computation
  const sortedData = useMemo(
    () => [...data].sort((a, b) => a.name.localeCompare(b.name)),
    [data]
  );

  // Memoize callback to prevent unnecessary re-renders
  const handleClick = useCallback(
    (rowId) => {
      onRowClick(rowId);
    },
    [onRowClick]
  );

  return (
    <div>
      {sortedData.map((row) => (
        <Row key={row.id} data={row} onClick={handleClick} />
      ))}
    </div>
  );
}

When to Use

When to Use

Good Use Cases

  1. Passing callbacks to memoized children
const Child = React.memo(({ onClick }) => ...);
const handleClick = useCallback(() => ..., []);
<Child onClick={handleClick} /> // Won't cause re-render
  1. Event handlers with dependencies
const handleSubmit = useCallback(
  (e) => {
    e.preventDefault();
    submitForm(formData);
  },
  [formData]
);
  1. Functions passed to useEffect
const fetchData = useCallback(async () => {
  const response = await fetch(url);
  return response.json();
}, [url]);

useEffect(() => {
  fetchData().then(setData);
}, [fetchData]);

When NOT to Use

  • Inline handlers (not passed as props)
  • Functions not used as dependencies
  • Simple functions (overhead > benefit)

Cost vs Benefit

// Don't useCallback for this
const handleClick = useCallback(() => {
  console.log("clicked");
}, []);
// Just use: onClick={() => console.log("clicked")}

// Do useCallback for this
const handleSort = useCallback(
  (key) => {
    setSortKey(key);
    setSortOrder((prev) => (prev === "asc" ? "desc" : "asc"));
  },
  []
);
// Pass to memoized child
<SortableList onSort={handleSort} />

Common Mistakes

// Bad: Creating new function every render
const handleClick = () => doSomething(id);

// Bad: Missing dependencies
const handleSubmit = useCallback(() => {
  submit(formData); // formData is missing!
}, []);

// Good: Include all dependencies
const handleSubmit = useCallback(() => {
  submit(formData);
}, [formData]);

Practice Problems

0/3solved
Build useCallback Component

Create a reusable React component implementing useCallback. Include proper state management and accessibility.

Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where needed
useCallback Testing

Write unit and integration tests for useCallback using React Testing Library.

Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility tests
useCallback Performance

Optimize useCallback for performance. Consider memoization, code splitting, and bundle size.

Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysis

Quiz

1. What does useCallback return?

Question 1 options

2. What is the difference between useCallback and useMemo?

Question 2 options

3. When should you use useCallback?

Question 3 options

4. What is referential equality?

Question 4 options

Flashcards

Question

What does useCallback do?

Answer

Returns a memoized function that only changes when dependencies change

Question

useCallback vs useMemo?

Answer

useCallback returns a function, useMemo returns a value

Question

When to use useCallback?

Answer

When passing callbacks to memoized children

Question

What is referential equality?

Answer

Two references pointing to the same object in memory

Question

What is useCallback?

Answer

useCallback is a key concept in frontend development.

Revision Notes

Key Takeaways

  • 1.useCallback memoizes functions
  • 2.Returns same function reference when dependencies unchanged
  • 3.useful with React.memo for child components
  • 4.Don't use for inline handlers
  • 5.Include all dependencies in the array

Interview Tips

  • Explain useCallback vs useMemo
  • Show how it works with React.memo
  • Discuss when it's beneficial vs unnecessary

Cheat Sheet

Cheat Sheet

Basic Usage

const handleClick = useCallback(() => {
  doSomething(a, b);
}, [a, b]);

With React.memo

const Child = React.memo(({ onClick }) => ...);
const handleClick = useCallback(() => ..., []);
<Child onClick={handleClick} />

useCallback vs useMemo

// useCallback for functions
const fn = useCallback(() => doStuff(), [dep]);

// useMemo for values
const value = useMemo(() => compute(dep), [dep]);

Common Pattern

const handleDelete = useCallback((id) => {
  setItems(prev => prev.filter(i => i.id !== id));
}, []);