Skip to content

How to use the useCallback React hook

New Course Coming Soon:

Get Really Good at Git

Find out what the useCallback React hook is useful for, and how to work with it!

Check out my React hooks introduction first, if you’re new to them.

One React hook I sometimes use is useCallback.

import React, { useCallback } from 'react'

This hook is useful when you have a component with a child frequently re-rendering, and you pass a callback to it:

import React, { useState, useCallback } from 'react'

const Counter = () => {
  const [count, setCount] = useState(0)
  const [otherCounter, setOtherCounter] = useState(0)

  const increment = () => {
    setCount(count + 1)
  }
  const decrement = () => {
    setCount(count - 1)
  }
  const incrementOtherCounter = () => {
    setOtherCounter(otherCounter + 1)
  }

  return (
    <>
      Count: {count}
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
      <button onClick={incrementOtherCounter}>incrementOtherCounter</button>
    </>
  )
}

ReactDOM.render(<Counter />, document.getElementById('app'))

The problem here is that any time the counter is updated, all the 3 functions are re-created again.

You can visualize this by instantiating a Set data structure, and adding each function to it. Why Set? because it only stores unique elements, which in our case means different (uniquely instantiated) functions.

import React, { useState, useCallback } from 'react'

const functionsCounter = new Set()

const Counter = () => {
  const [count, setCount] = useState(0)
  const [otherCounter, setOtherCounter] = useState(0)

  const increment = () => {
    setCount(count + 1)
  }
  const decrement = () => {
    setCount(count - 1)
  }
  const incrementOtherCounter = () => {
    setOtherCounter(otherCounter + 1)
  }

  functionsCounter.add(increment)
  functionsCounter.add(decrement)
  functionsCounter.add(incrementOtherCounter)

  alert(functionsCounter)

  return (
    <>
      Count: {count}
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
      <button onClick={incrementOtherCounter}>incrementOtherCounter</button>
    </>
  )
}

ReactDOM.render(<Counter />, document.getElementById('app'))

If you try out this code you’ll see the alert incrementing by 3 at a time.

What should happen instead it’s that if you increment one counter, all functions related to that counter should be re-instantiated.

If another state value is unchanged, it should not be touched.

Now, in most cases this is not a huge problem unless you are passing lots of different functions, all changing unrelated bits of data, that are proven to be a big cost for your app performance.

If that’s a problem, you can use useCallback.

This is how we do it. Instead of:

const increment = (() => {
  setCount(count + 1)
})
const decrement = (() => {
  setCount(count - 1)
})
const incrementOtherCounter = (() => {
  setOtherCounter(otherCounter + 1)
})

You wrap all those calls in:

const increment = useCallback(() => {
  setCount(count + 1)
}, [count])
const decrement = useCallback(() => {
  setCount(count - 1)
}, [count])
const incrementOtherCounter = useCallback(() => {
  setOtherCounter(otherCounter + 1)
}, [otherCounter])

Make sure you add that array as a second parameter to useCallback() with the state needed.

Now if you try to click one of the counters, only the functions related to the state that changes are going to be re-instantiated.

You can try this example on Codepen: https://codepen.io/flaviocopes/pen/VJQwzb/

Are you intimidated by Git? Can’t figure out merge vs rebase? Are you afraid of screwing up something any time you have to do something in Git? Do you rely on ChatGPT or random people’s answer on StackOverflow to fix your problems? Your coworkers are tired of explaining Git to you all the time? Git is something we all need to use, but few of us really master it. I created this course to improve your Git (and GitHub) knowledge at a radical level. A course that helps you feel less frustrated with Git. Launching May 21, 2024. Join the waiting list!
→ Get my React Beginner's Handbook
→ Read my full React Tutorial on The Valley of Code

Here is how can I help you: