Frequently Asked Questions

React useCallback() Hook: Concepts & Usage

What is the React useCallback() Hook?

The useCallback Hook memoizes a callback function to ensure it is not recreated on every render unless its dependencies change. This helps optimize performance in React applications by preventing unnecessary re-renders. Source

How does the useCallback Hook work in React?

The useCallback Hook takes two arguments: a callback function and a dependency array. On initial render, it returns the callback function. On subsequent renders, if dependencies haven't changed, it returns the same function instance; if any dependency changes, it returns a new memoized function. Source

What are the advantages of using useCallback in React applications?

The useCallback Hook improves performance by preventing unnecessary re-creations of callback functions, reduces memory usage by memoizing functions, enhances efficiency in components with frequent updates or complex logic, and ensures consistent behavior of callback functions across renders. Source

Can you provide an example of using the useCallback Hook in a React component?

Yes. Here is an example:

import { useState, useCallback } from 'react';
const Counter = () => {
  const [count, setCount] = useState(0);
  const incrementCounter = useCallback(() => { setCount(count + 1); }, [count]);
  const decrementCounter = useCallback(() => { setCount(count - 1); }, [count]);
  return (
    <div>
      Count: {count}
      <button onClick={incrementCounter}>Increment</button>
      <button onClick={decrementCounter}>Decrement</button>
    </div>
  );
};
This example demonstrates how useCallback prevents unnecessary re-creation of callbacks on every render. Source

What are the primary use cases for the useCallback Hook?

Primary use cases include optimizing performance by preventing unnecessary re-renders of child components, ensuring reference equality for callback functions passed as dependencies to other Hooks or memoized components, and avoiding recreating expensive functions on every render, especially when passed as props to child components. Source

When should you use the useCallback Hook in React?

Use useCallback when you need to optimize performance in lists, when a callback is a dependency in useEffect, when working with custom Hooks, to prevent stale closures, and when passing callbacks to child components to avoid unnecessary re-renders. Source

When is it unnecessary to use useCallback?

It is unnecessary to use useCallback for simple React components that do not re-render often, when the callback is only used within the component and not passed as a prop or used in a dependency array, or if the performance gain is negligible compared to the added complexity. Source

How does useCallback differ from useMemo?

useCallback memoizes a callback function, returning a memoized function instance, while useMemo memoizes a computed value, returning a memoized value of any type. useCallback is typically used for optimizing child component re-renders and dependency arrays of other Hooks, whereas useMemo is used for expensive calculations and creating stable objects. Source

What are best practices for using useCallback?

Best practices include using useCallback only at the top level of the component, pairing it with React.memo() for child components, including all necessary dependencies in the dependency array, and using it only when the performance benefit is clear. Source

How can useCallback help prevent unnecessary re-renders in React?

By memoizing callback functions, useCallback ensures that child components receiving these functions as props do not re-render unless the function reference actually changes, thus preventing unnecessary re-renders. Source

What problems can arise from not using useCallback in React?

Problems include unnecessary re-renders, increased memory usage, cascading re-renders in deeply nested component trees, and stale closures that can lead to bugs. Source

How do you use useCallback in a Hygraph-powered React e-commerce app?

In a Hygraph-powered React e-commerce app, useCallback can be used to memoize functions for toggling favorites and managing cart state, preventing unnecessary re-creations and improving performance, especially with many products. Source

Where can I find a simple blog project using Hygraph?

A simple blog project using Hygraph is available at this link.

Where can I read the Hygraph blog?

You can read the latest posts on the Hygraph blog.

What types of articles can be explored on the Hygraph blog?

The Hygraph blog features articles across categories such as Announcements, Headless CMS, and Content Strategy, covering topics like industry rankings, customer experience guides, and financial considerations for content platforms. Source

What is the main topic of the guide 'React useEffect() - A complete guide'?

The guide 'React useEffect() - A complete guide' provides a comprehensive explanation of the useEffect Hook in React, comparing it with useState, exploring its role with React Server Components, and offering practical examples. Source

Where can I learn more about React useEffect?

You can learn more about React useEffect in the complete guide published by Hygraph.

What does Hygraph's complete guide to React useEffect() cover?

The guide helps you master the React useEffect Hook, comparing it with useState and exploring its role with React Server Components, including practical examples. Published on August 26, 2024. Source

Hygraph Product Features & Capabilities

What features does Hygraph offer for content management?

Hygraph offers a GraphQL-native Headless CMS with features such as Smart Edge Cache for fast content delivery, content federation, custom roles for granular access control, rich text formatting, project backups, and high-performance endpoints. Source

How does Hygraph ensure high product performance?

Hygraph ensures high product performance through Smart Edge Cache, high-performance endpoints, and optimized GraphQL API usage. These features enable fast, reliable content delivery for global audiences. Source

What security and compliance certifications does Hygraph have?

Hygraph is SOC 2 Type 2 compliant (since August 3rd, 2022), ISO 27001 certified, and GDPR compliant, ensuring robust security and adherence to international standards. Source

How does Hygraph support enterprise-grade security?

Hygraph supports enterprise-grade security with granular permissions, SSO integrations, audit logs, encryption at rest and in transit, regular backups, dedicated hosting, custom SLAs, and compliance with GDPR and CCPA. Source

What feedback have customers given about Hygraph's ease of use?

Customers praise Hygraph's intuitive editor UI, accessibility for non-technical users, easy setup, and custom app integration. Hygraph was recognized for "Best Usability" in Summer 2023. Source

What are the key capabilities and benefits of Hygraph?

Key capabilities include operational efficiency, reduced costs, accelerated speed-to-market, scalability, GraphQL-native architecture, content federation, enterprise-grade security, Smart Edge Cache, custom roles, rich text formatting, and project backups. Source

How long does it take to implement Hygraph?

Implementation time varies by project. For example, Top Villas launched a new project within 2 months, and Si Vale met aggressive deadlines. Hygraph offers a free API playground, free developer account, structured onboarding, and extensive documentation for quick adoption. Source

What problems does Hygraph solve for businesses?

Hygraph solves operational inefficiencies, reduces developer dependency, modernizes legacy tech stacks, ensures content consistency, reduces costs, accelerates speed-to-market, simplifies schema evolution, resolves integration difficulties, and optimizes performance and localization. Source

Who is the target audience for Hygraph?

Hygraph targets developers, product managers, and marketing teams in industries such as ecommerce, automotive, technology, food and beverage, and manufacturing. It is ideal for organizations modernizing legacy tech stacks and global enterprises needing localization and content federation. Source

What customer success stories demonstrate Hygraph's impact?

Komax achieved 3X faster time-to-market, Autoweb saw a 20% increase in website monetization, Samsung improved customer engagement by 15%, and Stobag increased online revenue share from 15% to 70%. Source

What KPIs and metrics are associated with Hygraph's solutions?

KPIs include time saved on content updates, system uptime, content consistency across regions, user satisfaction scores, reduction in operational costs, speed to market, maintenance costs, scalability metrics, and performance during peak usage. Source

How does Hygraph differentiate itself in solving pain points?

Hygraph differentiates itself with a user-friendly interface, GraphQL-native architecture, content federation, cost efficiency, accelerated speed-to-market, extensive integration capabilities, robust APIs, Smart Edge Cache, and enhanced localization and asset management. Source

What is the overarching vision and mission of Hygraph?

Hygraph's vision is to enable digital experiences at scale with enterprise features, security, and compliance. Its mission is rooted in trust, collaboration, ownership, customer focus, continuous learning, transparency, and action-first values. Source

How does Hygraph handle value objections?

Hygraph addresses value objections by understanding customer needs, highlighting unique features, demonstrating ROI through reduced costs and accelerated speed-to-market, and sharing success stories such as Samsung's improved engagement. Source

What elements are included in a Hygraph blog page model?

A Hygraph blog page model includes slug, category, tag, title, description, authors, publishing date, cover image, content, and SEO metadata. Source

What is the significance of the Hygraph FM blog post?

The Hygraph FM blog post guides on adding pagination to Hygraph FM, enhancing user experience and SEO. Source

What does the blog post aim to uncover?

The blog post aims to uncover a legend about digital transformation and the awakening of a monolithic CMS. Source

See Hygraph MCP Server, AI Agents, and Editorial Experience Upgrades in Action

React useCallback() - A complete guide

Prevent unnecessary re-renders with React useCallback(). Learn the ins and outs of this powerful Hook and when and how to use it effectively.
Motunrayo Moronfolu

Written by Motunrayo 

Nov 07, 2024
React useCallback() - A complete guide

Performance optimization is crucial for creating a smoother user experience in modern web development. React, a popular JavaScript library for building user interfaces, provides several Hooks to help developers manage state and side effects efficiently. One such Hook is useCallback(), which plays a vital role in optimizing functional components by memoizing callback functions.

Whether you are a new React developer or someone looking to get more knowledge, this guide will provide you with insights about useCallback(), including its syntax, usage, common use cases, and best practices. We will also compare it with another Hook, useMemo().

#Understanding callback functions in React

Before explaining useCallback(), let’s start by understanding callback functions. In JavaScript, a callback function is a function that is passed as an argument to another function and is executed after some event or action has occurred.

Callback functions work the same way in the React context as in JavaScript, with the addition of being passed as props to child components. This allows children components to communicate with the parent component, enabling a flow of data and actions up the component tree.

Callback functions are an integral part of React apps as they perform activities like asynchronous operations (e.g., network requests) or handle events (e.g., clicks, form submissions, or other user interactions). For example, a button's onClick event handler may be defined as a callback function that updates the state of a React component or performs some action when the button is clicked. Like so:

const MyComponent = () => {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1);
};
return (
<button onClick={handleClick}>
Click me: {count}
</button>
);
};

In this example, handleClick is a callback function that increments the count state whenever the button is clicked.

Looking at this example, callback functions seem really handy and do what we need them to do. So why is there a need for useCallback()? That is because callback functions are not optimal in all cases, as we will explore in the next section.

The Product Launch That Redefines Headless CMS

See how Hygraph uses AI to drive content speed and precision.

#The problem with callback functions

Despite the usefulness of callback functions in React development, especially in handling events and interactions, they can lead to performance issues if not handled properly. The main problem stems from how React handles component re-rendering and how JavaScript treats functions as objects.

Let’s consider some common problems associated with callback functions in React:

Unnecessary re-renders

Functions are considered objects in JavaScript; as a result, every time a component renders or re-renders, any function inside that component is recreated as a new function object. This means that even if the function's logic remains exactly the same, React treats it as a new entity every time.

Consider this example:

function ParentComponent() {
const [count, setCount] = useState(0);
const handleClick = () => {
console.log('Button clicked');
};
return (
<div>
<p>Count: {count}</p>
<ChildComponent onClick={handleClick} />
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}

In this example, every time count changes and ParentComponent re-renders, a new handleClick function is created. From React's perspective, this new function is different from the current render of the previous one, even though its functionality hasn't changed.

Prop comparison and child re-renders

When a new function is created and passed as a prop, React sees this as a prop change. This can trigger the parent component to re-render the child component if the child is using optimization techniques like React.memo() or PureComponent. For example:

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

Even with React.memo, which is designed to prevent unnecessary re-renders, the ChildComponent will re-render every time ParentComponent renders because it receives a "new" onClick prop each time.

Stale closures

Callback functions can sometimes capture outdated values from their previous value, leading to bugs that are difficult to track and fix.

function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
const timer = setInterval(() => {
console.log(`Count is: ${count}`);
}, 1000);
return () => clearInterval(timer);
}, []);
return <button onClick={() => setCount(count + 1)}>Increment</button>;
}

In this counter component, the interval callback will always log 0 because it captures the initial value of count.

These problems lead to performance implications such as:

  • Cascading re-renders: In a deeply nested component tree, unnecessary re-renders can cascade down, causing significant performance overhead.
  • Unnecessary computations: Each re-render involves React's reconciliation process, which can be computationally expensive, especially for complex React components.
  • Increased memory usage: Creating new function instances repeatedly can lead to increased memory consumption over time.

These problems highlight the need for a way to manage callback functions in React applications. The useCallback() is designed to address these, and we will explore it in detail in the upcoming sections.

#What is useCallback()?

Stylized illustration of the React logo on a phone for a complete guide to the React 'useCallback' hook

useCallback() is a part of the built-in React Hooks that optimizes the performance of React applications by preventing unnecessary re-renders of components. It achieves this through memoizing callback functions, ensuring that they are only recreated when the dependency array changes.

Syntax and parameters

The useCallback() syntax looks like so:

const memoizedCallback = useCallback(() => {
// Your callback logic here
}, [dependency1, dependency2, ...]);

The useCallback() Hook takes two arguments:

  1. Callback function: This is the first argument, and it represents the function to memorize (remember).
  2. Dependency array: This second argument is an array of dependencies that determine when the callback function should be recreated. If any value in this array changes between renders, the callback function is recreated.

How useCallback() works

After adding useCallback(), React will memoize the provided function instance between re-renders. Here's what happens:

  1. On the initial render, React creates the function and returns it.
  2. On subsequent renders, React will:

    a. Check if any values in the dependency array have changed.

    b. If none have changed, it returns the same function instance from the previous render.

    c. If any have changed, it creates a new function instance and returns that.

This means that as long as the dependencies don't change, the exact same function instance is returned every time the component re-renders.

Let’s consider this example showing how useCallback() works:

function ParentComponent() {
const [count, setCount] = useState(0);
const increment = useCallback(() => {
setCount((c) => c + 1);
}, []); // Empty dependency array means this function never changes
return (
<div>
<p>Count: {count}</p>
<ChildComponent onIncrement={increment} />
</div>
);
}
const ChildComponent = React.memo(({ onIncrement }) => {
console.log('ChildComponent rendered');
return <button onClick={onIncrement}>Increment</button>;
});

In this example:

  • increment is a memoized function using useCallback(). It will only be recreated if the dependencies array (which are empty in this case) change.
  • ChildComponent is wrapped with React.memo to prevent unnecessary components re-render. It will only re-render if the prop changes.
  • Because increment is memoized, ChildComponent will not re-render when count changes in ParentComponent.

Now that we understand useCallback() and its proper usage, let us consider why knowing and using it might be beneficial in building React apps.

#When to use useCallback()

Here are some scenarios where using useCallback() is particularly beneficial:

  • Optimizing performance in lists: When rendering a list of items, you might need to pass a callback to each item. Using useCallback() ensures that the same callback instance is passed to each item, preventing unnecessary re-renders.
  • When a callback is a dependency in useEffect(): Use useCallback() when the callback is a dependency in a useEffect Hook to prevent the effect from running unnecessarily.
  • When working with custom Hooks: Use useCallback() to ensure consistent function references when creating custom Hooks that return callback functions, especially if these other functions will be used as dependencies in effects.
  • Preventing stale closures: When a callback function depends on state or props, using useCallback() helps to ensure the function always has the latest values.
  • Passing callbacks to child components: If the function references change, the child components may re-render unnecessarily. useCallback() helps prevent this by memoizing the function, ensuring it only changes when its dependencies change.

#When not to use useCallback()

While useCallback() is a powerful optimization tool, it may not be necessary in scenarios like:

  • For simple React components that do not re-render often.
  • When the callback is only used within the component and not passed as a prop or used in a dependency array.
  • If the performance gain is negligible compared to the added complexity.

It is important to always use Hooks appropriately to prevent unnecessary complexity or performance issues in the codebase.

#How to use useCallback() - Practical examples

Everything discussed is of little use if we cannot apply the knowledge to real-world applications. As a result, we will now explore using useCallback() in an e-commerce application. For this use case, we will focus on two functionalities:

  1. Adding items to "Favorites"
  2. Adding items to "Cart"

To do this, we will use Hygraph, a GraphQL-native headless content management system. Hygraph simplifies the development process by providing content management features while allowing developers to focus on building.

Create a React App

Set up a new React application using Vite by running the following command:

npm create vite@latest

Select React as the framework and complete the installation process. Additionally, install TailwindCSS for styling.

Start the development server using:

npm run dev

Now, check the terminal for the port the application is running on.

Setting up the Hygraph project

First, sign up for a free-forever developer account if you haven't already.

To use Hygraph in the React application, follow these steps:

  1. Clone the project: Clone this Hygraph eCommerce starter project to quickly set up a storefront. Once cloned, open the project.
  2. Configure API access: In the Hygraph project, navigate to Project Settings > API Access > Public Content API. Configure the Public Content API permissions to allow read requests without authentication. Click “Yes, initialize defaults” to add the necessary permissions for the High Performance Content API.
  3. Set environment variable: Locate the “High Performance Content API” and copy the URL. In the root folder of the React application, create a .env file and add the URL. Like so:
VITE_HYGRAPH_HIGH_PERFORMANCE_ENDPOINT=YOUR_URL

Substitute “YOUR_URL” with the appropriate URL.

Before working on the React app, explore Hygraph to understand the available content. Navigate to Hygraph’s API playground and run the query below to fetch product data, like so:

query GetProducts {
products {
images {
id
url
}
name
price
id
}
}

This query retrieves product information accessible via the “Content” view. Now, let’s fetch and display the product data in our React application.

Fetching data from Hygraph

Navigate to the project terminal and install the GraphQL client for fetching data:

npm add graphql-request

Open App.js and add the code below to fetch and display products:

import { useState, useEffect } from "react";
import { GraphQLClient, gql } from "graphql-request";
import "./App.css";
const endpoint = new GraphQLClient(
import.meta.env.VITE_HYGRAPH_HIGH_PERFORMANCE_ENDPOINT
);
const GET_PRODUCTS_QUERY = gql`
query GetProducts {
products {
images {
id
url
}
name
price
id
}
}
`;
function App() {
const [products, setProducts] = useState([]);
useEffect(() => {
const fetchProducts = async () => {
try {
const data = await endpoint.request(GET_PRODUCTS_QUERY);
setProducts(data.products);
} catch (error) {
console.error("Error fetching products:", error);
}
};
fetchProducts();
}, []);
return (
<div className="App container mx-auto p-4">
<h1 className="text-2xl font-bold mb-4">Product List</h1>
<ul className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
{products.map((product) => (
<li
key={product.id}
className="border rounded-lg p-4 shadow-md bg-gray-50">
<img
src={product.images[0].url}
alt={product.name}
className="w-full object-cover mb-4 rounded bg-white"
/>
<h2 className="text-lg font-semibold mb-2">{product.name}</h2>
<p className="text-gray-600 mb-2">
Price: ${(product.price / 100).toFixed(2)}
</p>
</li>
))}
</ul>
</div>
);
}
export default App;

The code above fetches data from Hygraph using the High Performance Content API. We also used the [useState](https://hygraph.com/blog/usestate-react) Hook, which manages the product data state, while the useEffect handles the data fetching.

At this point, we should have a screen that looks like this:

Product view

Next, let’s add a feature to mark products as “favorites” to demonstrate the usefulness of useCallback().

Adding favorite “functionality”

First, install FontAwesome for icons:

npm install @fortawesome/fontawesome-svg-core @fortawesome/free-solid-svg-icons @fortawesome/react-fontawesome

Update App.js to include the useCallback() Hook and FontAwesome icons:

import { useState, useEffect, useCallback } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faHeart } from "@fortawesome/free-solid-svg-icons";

In this case, we are using the heart icon to demonstrate the favorite in the UI.

Next, we will add a state:

const [favorites, setFavorites] = useState({});

This initializes the state variable favorites as an empty object and provides a function setFavorites to update the state. This function object allows toggling between two states, such as “favorited” or “not favorited”.

Next, we will declare the useCallback() :

const handleFavorite = useCallback((id) => {
setFavorites((prevFavorites) => ({
...prevFavorites,
[id]: !prevFavorites[id],
}));
}, []);

Here, we achieved the following:

  • We wrapped the handleFavorite function in a useCallback() to memoize it to prevent unnecessary re-creations on re-renders. This is especially beneficial for performance should the product item get larger applications with many products.
  • The function also toggled the favorite status of a product by updating the favorites state.

Now, we will complete this by adding the code below the “Price”:

<button
className="text-xl mr-2 heart-button"
onClick={() => handleFavorite (product.id)}>
<FontAwesomeIcon
icon={faHeart}
style={{ color: favorites[product.id] ? "red" : "grey" }}
/>
</button>

Here, we ensured that:

  • When a user clicks the button, it triggers the handleFavorite function declared earlier with the product's ID.
  • The color of the heart icon changes based on the favorite status stored in the favorites state object.

Now, we should be able to see a favorite icon in the UI for each product.

Using the useCallback() Hook here to toggle favorites on each product helps prevent unnecessary re-creations of the handleFavorite function on re-renders. This optimization is crucial in scenarios with many items. Now let us add the “add to cart functionality”.

Implementing “add to cart” feature

First, update the FontAwesome imports to include shopping cart icons:

import {
faHeart,
faCartShopping,
faPlus,
faMinus,
} from "@fortawesome/free-solid-svg-icons";

Add state and functions for handling the cart:

const [cart, setCart] = useState({});
const handleAddToCart = useCallback((product) => {
setCart((prevCart) => {
const quantity = prevCart[product.id]
? prevCart[product.id].quantity + 1
: 1;
return {
...prevCart,
[product.id]: { ...product, quantity },
};
});
}, []);
const handleRemoveFromCart = useCallback((productId) => {
setCart((prevCart) => {
if (!prevCart[productId]) return prevCart;
const newQuantity = prevCart[productId].quantity - 1;
if (newQuantity > 0) {
return {
...prevCart,
[productId]: { ...prevCart[productId], quantity: newQuantity },
};
} else {
const newCart = { ...prevCart };
delete newCart[productId];
return newCart;
}
});
}, []);

Here, we have two functions doing the following:

  • handleAddToCart: This function adds a product to the cart or increments its quantity if it already exists.
  • handleRemoveFromCart: This function decrements the quantity of a product in the cart or removes it if the quantity reaches 0.

Both functions use useCallback() to memoize the function and setCart to update the cart state.

Update the file to include cart controls:

<div className="flex justify-center items-center mt-3">
<FontAwesomeIcon icon={faCartShopping} className="mr-2" />
<button
className=" bg-gray-300 hover:bg-gray-400 rounded-full px-1"
onClick={() => handleAddToCart(product)}>
<FontAwesomeIcon icon={faPlus} />
</button>
<span className="mx-2">
{cart[product.id] ? cart[product.id].quantity : 0}
</span>
<button
className=" bg-gray-300 hover:bg-gray-400 rounded-full px-1"
onClick={() => handleRemoveFromCart(product.id)}>
<FontAwesomeIcon icon={faMinus} />
</button>
</div>

Finally, add a section to display the cart contents:

<div className="cart mt-8 p-4 border-t">
<h2 className="text-xl font-bold">
Cart ({Object.keys(cart).length} items)
</h2>
<ul className="mt-2">
{Object.values(cart).map((item, index) => (
<li key={index} className="mb-2 flex justify-between">
<span>
{item.name} - ${(item.price / 100).toFixed(2)}
</span>
<span>Quantity: {item.quantity}</span>
</li>
))}
</ul>
</div>

Your UI should now look like this:

Screenshot of a 'Product List' in a React app, showing six e-commerce items, used to demonstrate the 'useCallback' hook

Using useCallback() in this application helps improve performance as the number of products and interactions increases. It ensures that functions handling the internal state updates are not recreated unnecessarily.

You can access the code on GitHub.

#[object Object], vs. ,[object Object]

In React, both useCallback() and useMemo() are Hooks that optimize performance by memoizing values and functions, but they serve different purposes and are used in different scenarios.

With a syntax that looks like the below, useMemo() accepts two arguments (similar to useCallback()):

  • a function to calculate
  • a dependency array
const memoizedValue = useMemo(
() => computeExpensiveValue(a, b),
[a, b], // Dependency array
);

When comparing useCallback() with useMemo(), the differences are best based on what they memoize, return, and their use cases, as this sometimes shows the mistaken line between the two Hooks.

Considerations useCallback() useMemo()
What they memoize Memoizes a callback function Memoizes computed value
Return value Returns a memoized callback function Returns a memoized value (which can be a new value of any type)
Use Typically for optimizing child component re-renders and in dependency arrays of other Hooks For expensive, complex calculations and creating objects that should remain stable

Consider this useMemo() example:

import React, { useMemo } from 'react';
const computeExpensiveValue = (a, b) => {
console.log('Computing expensive value...');
let result = 0;
for (let i = 0; i < 1000000000; i++) {
result += a + b;
}
return result;
};
const App = () => {
const a = 5;
const b = 10;
const expensiveValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
console.log(`Expensive value for a=${a} and b=${b}: ${expensiveValue}`);
return null;
};
export default App;

In this example, useMemo() memoizes the result of computeExpensiveValue(). The computation will only re-run if a or b changes, avoiding unnecessary recalculations on every render. This is in contrast to useCallback(), where the function itself would be memoized, but the expensive computation would still run every time the function is called, even if a and b haven't changed.

Now that we have explored the difference between useCallback() and useMemo(), let’s consider when it is best to use useCallback().

#Best practices for using ,[object Object]

  • Like any other Hook, useCallback() should only be used at the top level of the component and outside of any loop or condition.
  • Pair useCallback() with [React.memo()](https://hygraph.com/blog/react-memo) for child components to prevent unnecessary re-renders when the callback function's reference hasn't changed.
  • The dependency array is crucial, and omitting necessary dependencies can cause bugs. In the dependency array, include all values from the component scope that the callback function depends on.
  • It goes without saying that useCallback() should only be used if and when necessary. As such, only use useCallback() when the performance benefit is obvious.

#Conclusion

This guide provides an overview of the React useCallback Hook, from the problem it solves to its use cases and best practices for its implementation.

Join the Hygraph developer workspace to discover exciting innovations and connect with other developers. It’s also a great place to interact with the Hygraph team, share insights, and expand your skills.

Blog Author

Motunrayo Moronfolu

Motunrayo Moronfolu

Technical writer

Motunrayo Moronfolu is a Senior Frontend Engineer and Technical writer passionate about building and writing about great user experiences.

Share with others

Sign up for our newsletter!

Be the first to know about releases and industry news and insights.