useCallback in React: Memoizing Functions to Prevent Re-Creation
Shefali

Shefali @devshefali

About: I am a passionate web developer from India. I find pleasure in talking about programming and I love to help everyone who needs any guidance related to programming.

Location:
India
Joined:
Jun 12, 2023

useCallback in React: Memoizing Functions to Prevent Re-Creation

Publish Date: May 27
9 8

In React applications, unnecessary function re-creation can lead to performance issues, especially when passing functions as props to child components. This is where the useCallback in React comes in.

In this blog, you’ll learn about the useCallback hook, including its use case and syntax with examples, and the key difference between the useCallback and useMemo hooks.

Before we get started, don’t forget to subscribe to my newsletter!
Get the latest tips, tools, and resources to level up your web development skills delivered straight to your inbox. Subscribe here!

Now, let’s jump right into it!

What is useCallback?

useCallback is a React Hook that memoizes functions. This stores the reference of the function so that you can avoid creating a new function on each render.

This improves the performance, especially when you need to pass functions from parent components to child components.

If a function is creating unnecessary, then it’s a best practice to use the useCallback hook.


Basic Syntax of useCallback

Before using useCallback, you need to import it from React:

import { useCallback } from "react";
Enter fullscreen mode Exit fullscreen mode

Syntax:

const memoizedFunction = useCallback(() => {
  // Function logic
}, [dependencies]);
Enter fullscreen mode Exit fullscreen mode

Here,

  • useCallback accepts a function that gets memoized.
  • The function will be re-created only when the dependencies change.
  • If dependencies are the same, then the same function reference will be returned.

Function Re-Creation Without useCallback

If you don’t use the useCallback hook, then on each render, a new function will be created, which causes unnecessary renders.

import { useState } from "react";

function ChildComponent({ handleClick }) {
  console.log("Child re-rendered!"); // The child component re-render on each render

  return <button onClick={handleClick}>Click Me</button>;
}

export default function App() {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    console.log("Button clicked!");
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <ChildComponent handleClick={handleClick} />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

How does it work?

Child Component (ChildComponent):

  • Accepts handleClick as a prop.
  • Logs “Child re-rendered!” on every render.
  • Renders a button that calls handleClick when clicked.

Parent Component (App):

  • Uses useState to manage count.
  • Defines the handleClick function (logs “Button clicked!”).
  • Renders:
    • A paragraph showing count.
    • A button to increment the count.
    • ChildComponent, passing handleClick as a prop.

Re-render Issue:

  • On every App re-render (when count updates), handleClick is recreated.
  • Since a new function reference is passed, ChildComponent also re-renders unnecessarily.

Function Re-Creation Avoided With useCallback

You can avoid the unnecessary function re-creation using useCallback.

import { useState, useCallback } from "react";

function ChildComponent({ handleClick }) {
  console.log("Child re-rendered!"); // This will only re-render when function changes

  return <button onClick={handleClick}>Click Me</button>;
}

export default function App() {
  const [count, setCount] = useState(0);

  const handleClick = useCallback(() => {
    console.log("Button clicked!");
  }, []); // Function reference will not change

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <ChildComponent handleClick={handleClick} />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

How does it work?

Child Component (ChildComponent):

  • Accepts handleClick as a prop.
  • Logs “Child re-rendered!” on render.
  • Renders a button that calls handleClick when clicked.

Parent Component (App):

  • Uses useState to manage count.
  • Wraps handleClick with useCallback (dependency array [ ] ensures function reference remains stable).
  • Renders:
    • A paragraph showing count.
    • A button to increment the count.
    • ChildComponent, passing the memoized handleClick.

Optimization with useCallback:

  • Now, the handleClick reference does not change on re-renders.
  • ChildComponent only re-renders when necessary, reducing unnecessary renders.

Event Handlers in useCallback

If an event handler is repeatedly re-created, then you can optimize this by using the useCallback.

Without useCallback (Unoptimized Code)

import { useState } from "react";

export default function App() {
  const [count, setCount] = useState(0);

  const increment = () => setCount(count + 1); // New function is creating on each render

  return <button onClick={increment}>Count: {count}</button>;
}
Enter fullscreen mode Exit fullscreen mode

How does it work?

Defines increment Function:

  • Increments count by 1.
  • Created inside the component, so a new function is created on every render.

Returns a Button:

  • Displays count.
  • Calls increment on click.

Issue: Unnecessary function re-creation

  • On each re-render, a new instance of increment is created.
  • This can cause performance issues if passed as a prop to child components.

With useCallback (Optimized Code)

import { useState, useCallback } from "react";

export default function App() {
  const [count, setCount] = useState(0);

  const increment = useCallback(() => setCount(count + 1), [count]); // Memoized function

  return <button onClick={increment}>Count: {count}</button>;
}
Enter fullscreen mode Exit fullscreen mode

How does it work?

Defines increment Function:

  • Wrapped in useCallback with [count] as a dependency.
  • Memoizes increment, so a new function is created only when count changes.

Returns a Button:

  • Displays count.
  • Calls increment on click.

Why is this better than the previous version?

  • Prevents unnecessary function re-creation on each render.
  • Useful when passing increment as a prop to child components.

useCallback in API Calls & Dependencies

If a function calls an API or depends on a state, then you can optimize that by using the useCallback.

import { useState, useCallback } from "react";

export default function App() {
  const [query, setQuery] = useState("");

  const fetchData = useCallback(() => {
    console.log("Fetching data for:", query);
    // API call logic
  }, [query]); // Function will recreate only when the `query` changes

  return (
    <div>
      <input onChange={(e) => setQuery(e.target.value)} />
      <button onClick={fetchData}>Search</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

How does it work?

Defines fetchData Function:

  • Logs “Fetching data for:” along with the current query.
  • Wrapped in useCallback with [query] as a dependency.
  • This ensures that fetchData is only recreated when the query changes.

Returns an Input Field & Button:

  • The input updates the query on every change.
  • The button triggers fetchData to “fetch data” for the current query.

Optimization Benefit:

  • Prevents unnecessary re-creation of fetchData unless query changes.
  • Useful when passing fetchData to child components to avoid unnecessary re-renders.

What is the difference between useCallback and useMemo?

Feature useCallback useMemo
Purpose Function memoization Value memoization
Returns Memoized function reference Memoized computed value
Use Case When unnecessary function recreation happening When expensive calculation is happening repeatedly

In simple:

  • If you need to memoize a function, use useCallback.
  • If you need to memoize a computed value or expensive calculation, use useMemo.

🎯Wrapping Up

That’s all for today!

For paid collaboration connect with me at : connect@shefali.dev

I hope this post helps you.

If you found this post helpful, here’s how you can support my work:
Buy me a coffee – Every little contribution keeps me motivated!
📩 Subscribe to my newsletter – Get the latest tech tips, tools & resources.
𝕏 Follow me on X (Twitter) – I share daily web development tips & insights.

Keep coding & happy learning!

Comments 8 total

  • Engineer Robin 🎭
    Engineer Robin 🎭May 27, 2025

    Brilliantly explained, Shefali! 🙌 Your article on useCallback dives deep into one of the most essential React hooks with such clarity. Memoization can be tricky for many, but your real-world examples and practical insights make it so much easier to understand. Definitely bookmarking this one! 🔥✨

  • KC
    KCMay 28, 2025

    I've been following your articles and I can't be grateful enough. Each of them helps me to refresh my practice on React

    • Shefali
      ShefaliMay 28, 2025

      That means a lot! Thank you so very much🙏

  • Dotallio
    DotallioMay 28, 2025

    Really clear breakdown, especially how you showed the child component re-render case - I've run into that way too often. Have you ever had a moment where useCallback didn't fix the extra renders and you had to dig deeper?

  • Nathan Tarbert
    Nathan TarbertMay 28, 2025

    pretty cool seeing this laid out with examples. you think people sometimes overuse memoization hooks or nah?

  • Beverley fonder
    Beverley fonderMay 31, 2025

    Rating: ⭐⭐⭐⭐⭐ (5/5)
    Highly recommend!

    If you're suspicious your partner is cheating and you feel stuck, I totally get it been there. What really helped me was reaching out to a mobile phone monitoring expert who knew exactly what to do. I contacted (Zattechhacker AT gmail com ), and honestly, they were a lifesaver. They remotely accessed my partner’s phone (discreetly and securely) and gave me a private link to track his live location and phone activity. That’s how I found out he was hooking up with someone at his office. I confronted him with all the evidence and he had nothing to say. The proof was undeniable. If you're in a tough spot and need real answers, don’t wait. Reach out to (Zattechhacker AT gmail com ) or message them on Gmail (Zattechhacker AT gmail com ). They really know their stuff when it comes to tracking and monitoring phones.

Add comment