useCallback
Definition
`useCallback` is a React Hook that lets you cache a function definition between re-renders. It is primarily used to prevent unnecessary re-renders of child components that rely on reference equality to avoid updating.
Explain Like I'm New
Imagine you have a 'recipe' (a function) for baking cookies. Every time you clean your kitchen (re-render), you throw away the old recipe and write a brand new identical recipe. If you hand that recipe to your friend (a child component), they think it's a completely new recipe and they start baking again! `useCallback` is like laminating the recipe. You keep the exact same physical copy, so your friend knows nothing has changed.
Real World Example
You have a massive `<HeavyChart />` component wrapped in `React.memo()`. You pass it an `onClick={handlePointClick}` function. If you don't wrap `handlePointClick` in `useCallback`, a brand new function is created in memory on every render. The Chart sees a 'new' function prop, and re-renders entirely, completely defeating `React.memo`.
Common Use Cases
- •Passing stable callback functions to heavily optimized child components (like those using `React.memo`)
- •Preventing infinite loops when a function is used as a dependency in a `useEffect` array
React Performance Hooks Comparison
| Hook | What it caches | Primary Use Case |
|---|---|---|
| `useCallback` | A Function Definition | Preventing a child component from unnecessarily re-rendering when you pass it a callback function as a prop. |
| `useMemo` | A Computed Value | Preventing an expensive math calculation or data filtering operation from running on every single render. |
| `useEffect` | Nothing (Runs side-effects) | Fetching data, setting up subscriptions, or manually changing the DOM. |
Interactive Example
import React, { useState, useCallback } from 'react'; // A child component heavily optimized with React.memo // It will ONLY re-render if 'title' or 'onAction' changes in memory. const HeavyChild = React.memo(({ title, onAction }) => { console.log("HeavyChild rendered!"); return <button onClick={onAction}>{title}</button>; }); export default function ParentComponent() { const [count, setCount] = useState(0); // BAD: This creates a brand new function in memory every time Parent renders. // If we passed this, HeavyChild would re-render every time 'count' changes. // const handleAction = () => console.log("Action!"); // GOOD: useCallback caches the function in memory. // It will always be the exact same function reference. const handleAction = useCallback(() => { console.log("Action clicked!"); }, []); // Empty array means it never needs to be recreated return ( <div> <h2>Parent Count: {count}</h2> <button onClick={() => setCount(c => c + 1)}>Increment Parent</button> <hr /> {/* Passing the cached function to the optimized child */} <HeavyChild title="Click Me" onAction={handleAction} /> </div> ); }
Interview Questions
basic
- What is the main purpose of `useCallback`?
- How is `useCallback` different from `useMemo`?
intermediate
- If you wrap a function in `useCallback`, but you don't pass it to a child component, is it helping performance?
- What causes a `useCallback` function to be recreated?
advanced
- Why is inline function creation (e.g., `onClick={() => doSomething()}`) usually perfectly fine for standard DOM elements like `<button>`?
- How does JavaScript's concept of 'Reference Equality' apply to `useCallback`?
trick
- Does `useCallback` make your component render faster?