Learn How To Use The UseCallback Hook

React

10/06/2021


The useCallback hook in React is used whenever you want to prevent an inline function (i.e. a function inside a React component) from being created on each render. Let me show you what I mean by that.

Reference equality

How does React know whether a function is newly created or is memoized from a previous render. Reference equality is the name of the game. ✊

Take a look at the example below where we call a factory function that returns another function, much like useCallback! We store the returned functions and then compare them.

JAVASCRIPT
function factory() {
return () => console.log('Woah...')
}
const funcA = factory()
const funcB = factory()
funcA() // Woah...
funcB() // Woah...
console.log(funcA === funcA) // true
console.log(funcA === funcB) // false

You might (wrongly ❌) presume that funcA and funcB are identical as they were returned by the same function. However, they are both stored in different places in memory, which is why the comparison equates to false.

Thus, comparing by reference simply means comparing the storage location of the function.

The issue

I created an interactive (yes, interactive!) example, made up of a Parent and Child component.

  • The parent contains a counter, and an increment function which is passed down to the child, while
  • The child has the function attached to a button's onClick event.

Pay attention 🚨 in particular to the useEffect hook that gets triggered whenever it detects a different copy of increment.

Whenever you click on the "Increment" button, you'll see that our function gets created on every render of the parent.

Be sure to have your browser's console open so you can see the logs.

The solution

To prevent this from happening, simply wrap the function in a useCallback hook.

DIFF
- const increment = () => setCount(prevCount => prevCount + 1)
+ const increment = React.useCallback(() => setCount(prevCount => prevCount + 1), [setCount])

The 1st function argument simply takes in our increment function from earlier, while the 2nd argument accepts a dependency array, much like useEffect.

Once you apply these changes to increment, which I encourage you do in the live editor, you'll notice the function only gets created once (on page load).

When to use

If you aren't familiar with memoization in JavaScript, I recommend you check out 👉 my article. I point out how you shouldn't prematurely optimize as it might worsen performance, not improve it. The same principle applies to useCallback.

So when should you use this hook? In my opinion, when

  • Your inline function becomes noticeably expensive, or
  • If your function frequently or unintentionally triggers a re-render of other hooks and/or components

WRITTEN BY

Code and stuff