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.
function factory() { return () => console.log('Woah...')}
const funcA = factory()const funcB = factory()
funcA() // Woah...funcB() // Woah...
console.log(funcA === funcA) // trueconsole.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.
- 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