React Grimoire
  • ⁉️Introduction
  • 🧑‍🎓🧑🎓 React Fundamentals
    • The Basic javascript "Hello world"
    • Basic view on React core API's
    • JSX
    • React Props and styling
    • Components
    • Handling Events With React
    • Form
    • Array and Lists
    • Class Component State
    • Class Component Life Cycle
    • PropTypes
  • 🪝React Hooks
    • Intro to hooks
    • useState
    • useEffect
    • useRef
    • useContext
    • useMemo
    • useCallback
    • useReducer
    • useLayoutEffect
    • useImperativeHandle
    • Hook flow
    • Custom hooks
      • useDebugValue
    • React 18 hooks
  • 📓React Guidelines
    • React Components Composition Guidelines
    • React hooks guidelines
    • The use of Memoization
    • Lifting State Up
  • 🔭Concepts
    • Advanced Patterns
      • Compound Components Pattern
      • Control Props Pattern
      • Props Getters Pattern
      • Custom hook pattern
      • Context Module
      • State Reducer
    • React Under the hood
      • 🏁What is "Rendering"?
      • 🏁React Lifecycle
      • 🏁Reconciliation & Virtual DOM in React
      • 🏁Fiber
    • ⏰Concepts to always have in mind
  • 🧩React ecosystem
    • Forms Tools
      • React Hook Form VS Formik
    • TypeScript
      • 🏁Conditional React props with TypeScript
    • 🏁Build tool choice for MVP projects
    • A CSS methodology comparison
      • 🏁Post CSS processor :Sass
      • 🏁CSS in js :Styled-components
      • 🏁Utility Classes: Tailwind
  • ⁉️Testing
    • In Progress
  • 🎭Performance
    • in Progress
  • 🚀Deployment
    • In Progress
  • 🖼️Design system
    • 🏁What's a design system anyway ?​?
  • 🔗Us-full links
    • Typescript and React basic tutorial
    • React-philosophies
    • React new doc
Powered by GitBook
On this page
  • Purpose of useCallback
  • A use case where we should adopt useCallback()
  • A use case where we shouldn't adopt useCallback()
  • Working with useCallback vs. useMemo in React
  • useCallback and useMemo anti-patterns

Was this helpful?

Edit on GitHub
  1. React Hooks

useCallback

PrevioususeMemoNextuseReducer

Last updated 3 years ago

Was this helpful?

The goal of useCallback is to avoid unnecessary re-renderings; it accepts two values: a memorized function and an array of dependencies that will update this function whenever any of the values change.

When a function is wrapped with useCallback, React saves a reference to it. To reduce rendering time, pass this reference as a property to new components.

Purpose of useCallback

function MyComponent() {
  // handleClick is re-created on each render
  const handleClick = () => {
    console.log('Clicked!');
  };
 ...
}

On each rendering of MyComponent, handleClick is a different function object.

But in some cases you need to maintain a single function instance between renderings:

  1. A functional component wrapped inside React.memo() accepts a function object prop

  2. When the function object is a dependency to other hooks, e.g. useEffect(..., [callback])

This is where useCallback(callbackFun, deps) comes in handy: Given the same deps, the hook returns (aka memoizes) the function instance between renderings:

import { useCallback } from 'react';

function MyComponent() {
  // handleClick is the same function object
  const handleClick = useCallback(() => {
    console.log('Clicked!');
  }, []);
 ...
}

A use case where we should adopt useCallback()

Imagine you have a component that renders a big list of items:

import useSearch from './useSearch';

function MyBigList({ term, onItemClick }) {
  const items = useSearch(term);
  
  const map = (item) => <div onClick={onItemClick}>{item}</div>;
  
  return <div>{items.map(map)}</div>;
}
export default React.memo(MyBigList)

The list could be lengthy, possibly containing hundreds of items. You wrap it in React.memo to avoid unnecessary list re-renderings ().

The parent component of MyBigList provides a handler function to know when an item is clicked:

import * as React from 'react';

export function MyParent({ term }) {
  const onItemClick = React.useCallback(
    (event) => {
      console.log('You clicked ', event.currentTarget);
    },
    [term],
  );
  return <MyBigList term={term} onItemClick={onItemClick} />;
}

When MyParent component re-renders, onItemClick function object remains the same and doesn't break the memoization of MyBigList.

That was a good use case of useCallback().

A use case where we shouldn't adopt useCallback()

Let's look at another example:

import * as React from 'react';

function MyComponent() {
  // Contrived use of `useCallback()`
  const handleClick = useCallback(() => {
    // handle the click event
  }, []);
  return <MyChild onClick={handleClick} />;
}
function MyChild({ onClick }) {
  return <button onClick={onClick}>I am a child</button>;
}

Does it make sense to apply useCallback()? Most likely not because <MyChild> component is light and its re-rendering doesn't create performance issues.

Don't forget that useCallback() hook is called every time MyComponent renders. Even useCallback() returning the same function object, still, the inline function is re-created on every re-rendering (useCallback() just skips it).

By using useCallback() you also increased code complexity. You have to keep the deps of useCallback(..., deps) in sync with what you're using inside the memoized callback.

In conclusion, the optimization costs more than not having the optimization.

Simply accept that rendering creates new function objects:

import * as React from 'react';
function MyComponent() {
  const handleClick = () => {
    // handle the click event
  };
  return <MyChild onClick={handleClick} />;
}
function MyChild({ onClick }) {
  return <button onClick={onClick}>I am a child</button>;
}

Working with useCallback vs. useMemo in React

The useCallback and useMemo functions appear similar on the surface. However, there are particular use cases for each.

Wrap functions with useCallback when:

  • Wrapping a functional component in React.memo() that accepts your method as a property

  • Passing a function as a dependency to other hooks

Utilize useMemo:

  • For functions whose inputs change gradually

  • When data values are not so large that they pose a potential memory issue

  • When parameters are not so small that the cost of comparisons outweighs the use of the wrapper

A callback works well when code would otherwise be recompiled with every call. Memorizing results can help decrease the cost of repeatedly calling functions when the inputs change gradually over time. On the other hand, in the trading example, we may not want to memorize results for a constantly changing order book.

useCallback and useMemo anti-patterns

It can be tempting to think you can make use of useCallback or useMemo … but this is not the case. There is overhead associated with wrapping functions. Each call requires extra work to unravel your function call and decide how to proceed.

🪝
for every function