React useCallback Hook Explained with Examples and Best Practices 2025 Guide bilal shafqat

React useCallback Hook Explained with Examples and Best Practices (2025 Guide)

Introduction

React’s useCallback is one of those hooks that seems confusing at first — until you start dealing with unnecessary re-renders or memoized components.

In React, functions are re-created on every render. This behavior is harmless in most cases, but when passing callbacks to deeply nested or memoized child components, re-creating the function can cause unnecessary re-renders and performance issues.

This is where useCallback shines.

In this guide, you’ll learn:

  • What useCallback is
  • How it works and why it exists
  • How it compares to useMemo and inline functions
  • When to use it — and when not to
  • Real-world use cases with code examples

What is useCallback?

What is useCallback bilal shafqat

useCallback is a built-in React hook that lets you memoize a function — meaning it returns the same function reference between renders unless one of its dependencies has changed.

Syntax:

const memoizedFn = useCallback(() => {
  // your logic
}, [dependencies]);

If none of the dependencies change, React will return the exact same function — avoiding unnecessary function recreation and preventing extra renders in child components.

Why is this useful?

When you pass a function as a prop to a memoized child component (e.g., using React.memo), even a new function reference — with identical logic — can cause that component to re-render.

useCallback ensures that the function reference remains stable, helping with performance and preventing extra renders.

Example 1: Memoizing a Handler

import { useCallback, useState } from 'react';

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

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

  return <Child onClick={increment} />;
}

Without useCallback, the increment function would be re-created on every render, potentially triggering unnecessary renders in Child.

useCallback vs useMemo

Both useCallback and useMemo help with memoization — but they do different things.

Feature useCallback useMemo
Purpose Memoize functions Memoize values (returned from functions)
Return type A function Any value (array, object, result)
Use case Event handlers, props Expensive calculations, filtered arrays

Example 2: useCallback vs Inline Function

Inline Function:

<Button onClick={() => doSomething()} />

With useCallback:

const handleClick = useCallback(() => doSomething(), []);
<Button onClick={handleClick} />

In the first case, a new function is created every render.
In the second case, handleClick stays the same between renders — avoiding unnecessary re-renders of Button.

Real Use Case: Avoid Re-rendering Memoized Children

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

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

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

  return (
    <>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <Child onClick={handleClick} />
    </>
  );
}

Here, Child will NOT re-render unless handleClick changes — which it won’t, thanks to useCallback().

When to Use useCallback

  • You’re passing a function as a prop to a memoized child component
  • You want to avoid unnecessary function recreation
  • You’re building reusable components or component libraries
  • You’re using a stable callback in an effect

When NOT to Use useCallback

  • Your function doesn’t affect performance when recreated
  • You’re not passing it to memoized children
  • Your dependencies change frequently (useCallback won’t help much)

Note: Don’t use useCallback everywhere “just in case.” It adds complexity and memory overhead. Use it when it solves a specific performance issue.

Common Mistakes with useCallback

1. Overusing it

Don’t wrap every function in useCallback by default. Only use it for actual memoization needs.

2. Missing dependencies

useCallback(() => {
  doSomething(message);
}, []); // 🚫 'message' should be in dependencies

3. Using it without memoized children

If you’re not using React.memo or passing functions to children, useCallback might have no benefit.

Best Practices for useCallback (2025)

  • Use with React.memo to prevent child re-renders
  • Use with stable dependencies to avoid re-creating the function
  • Combine with useEffect when passing a callback that must not change
  • Profile performance with dev tools before applying
  • Clean up side effects when passing memoized callbacks to useEffect

Summary: Master useCallback to Improve React Performance

useCallback is not just a “nice to have” — it’s essential when building performant React apps with lots of components or heavy rendering logic.

Remember:

  • It returns a memoized version of your function
  • It helps avoid unnecessary re-renders
  • It should be used selectively — not everywhere

If you work with React.memo, nested components, or reusable hooks — useCallback is your best friend.

Leave A Comment