Learn How to Tame React's useCallback Hook

Apr 28, 2022
Illustration of a woman facing a computer screen, holding her hands up in a perplexed manner.

One of the major reasons for its rise was the release of hooks in Version 16.8. React hooks let you tap into React functionality without having the ability to create classes for your components. Now functional components with hooks are the preferred method of working with React.

In this blog, we'll dig deeper into the specific feature -- callback due to the fact that it will touch on a essential aspect of functional programming known as memoization.

By the end of this article, you'll know exactly how and when to utilize the useCallback hook, as well as how to make the best of its performance-enhancing capabilities.

Ready? We're ready to dive right in!


What exactly is Memoization?

A memory function is one in which the function stores its output so the next time it is executed with the same input, it is able to skip any of the complicated calculations and simply return to you its output that it previously determined.

It can also have an enormous impact on memory allocation and efficiency, and this stress is exactly what is the callback hook was designed to alleviate.

React's useCallback vs useMemo

It's important to mention that useCallback is a great match with another hook, which is useMemo. We'll discuss them both however in this article we'll focus on useCallback as the primary topic.

The key difference is that the useMemo method returns a memoized value, whereas callback returns a memoized function. This means that useMemo is used to save an uncalculated value, and callback gives you a function you can call later on.

These hooks give you back the cached version in case any of their dependencies (e.g. props or states) alters.

Let's take a look at the two functions in action:

import  useMemo, useCallback  from 'react'
const values = [3, 9, 6 4, 2 1]The result will always be the exact value, which is an array of numbers. If the array of values changes, the algorithm will have to recompute. Const memoizedValue = UseMemo(() => values.sort() *, [valuesvalues)
// This will provide me a function which is able to be invoked later. It always returns the same result regardless of whether the array with values is altered. const memoizedFunction = useCallback(() => values.sort(), [values])

The above code example is a contrived example but illustrates the differences between two methods of callback:

  1. memoizedValue is now the array [1,2 3 4, 6 9. As long as the values variable stays so will memoizedValue and will never recompute.
  2. memoizedFunction will be a function that when called returns the array [1,2 3 4, 6, 9].

The great thing about these callbacks is that they are cached, and stay indefinitely until the array of dependencies changes. So, when they render, they won't get garbage gathered.

Rendering and React

How important is memoization when it comes to React?

This is due to the way React renders your component. React makes use of a VirtualDOM stored in memory to compare information and determine what data to update.

The virtual DOM is what helps React with performance and helps keep your application running fast. When a value in your component changes then the whole component will render again. This is why React "reactive" in response to user input and allows for the page to be updated without having to reload the webpage.

However, there could be times you don't need to render your components since changes will not affect the component. This is where memoization through useCallback as well as useMemo is useful.

As React renders your part, it also recreates your declared functions within the component.

Are you interested in knowing what we did to increase our visitors by 1000%?

Join 20,000+ others who receive our newsletter every week with insider WordPress advice!

When comparing the importance of a function against another one, it are always false. Because a function is also an object, it will only equal itself:

// these variables contain the exact same purpose, however they're not the sameconst hello = () = console.log('Hello Matt')
 const hello2 = () = console.log('Hello Matt')
 
hello= hello2 // false
greeting is helloTrue

That is, when React re-renders components, React will view the functions declared within your component as new functions.

It's okay for the majority of cases, and simple functions are easy to calculate and won't affect performance. But the other times when you don't want your program to be perceived as being a brand new feature, it is possible to rely on callback to assist you.

It is possible that you are thinking "When should I expect an application to be viewed as a new method?" Well, there are certain cases when using callback makes more sense:

  1. This function will be passed on to a different component which is also memorized ( useMemo)
  2. Your body's function is in an internal state that it requires to be able to recall
  3. The function you are using is dependent of another hook. For example, useEffect to name a few examples.

The Performance Benefits of React's useCallback

When you make sure that useCallback is used correctly, it can help to improve the speed of your application as well as stop components from rendering again if they do not need to.

For instance there is a program that retrieves a lot of data , and is responsible for displaying those data as part of charts or graph such as:

A colorful bar graph comparing the overall transaction time of PHP, MySQL, Reddis, and external (other) in milliseconds.
Bar graphs generated by the React component

If the parent component of your data visualization's component re-renders and the props or states which changed don't affect the component in any way, then you probably don't require or want to re-render it, and then refetch the entire data. Refetching and re-rendering will save bandwidth for your users and provide them with more user-friendly experience.

The drawbacks to React's useCallback

While this method can assist to improve your performance, it also comes with its drawbacks. Things to think about prior to using useCallback (and useMemo) are:

  • Garbage collection The functions not yet written down will be discarded through React in order to free memory.
  • Memory allocation Similar to garbage collection and garbage collection, the more memoized functions you've implemented and the larger memory amount that will require. Plus, each when you call these functions you'll find a lot of code inside React which requires an additional amount of memory in order in order to deliver the cached output.
  • Code complexity: When you start creating hooks that wrap functions it immediately increases the level of complexity in your code. The code now requires greater understanding of why these hooks are employed as well as confirmation that they are being used correctly.

Knowing about the above pitfalls can save you the headache of stumbling across them yourself. In the event you decide to use useCallback, just be sure your performance advantages will be greater than the drawbacks.

Example

Below is a simple setup with a Button component as well as a Counter component. The Counter contains two parts of state that render two Button components, each that will update a separate piece of the Counter components state.

The Button component is comprised of two props: handleClick and name. Each time the Button gets rendered, the Button will send a log into the console.

import useCallback and useState from'reactconst Button = (handleClick, name) (handleClick, name) 
 console.log (`$name rendered)
 return the name
Const Counter = () *

If you hit either button the following will appear on the console screen:

// counter rendered
 
 // button1 rendered
 // button2 rendered

Then, if we attach useCallback to the handleClick function and wrap our Button in React.memo We can observe the benefits useCallback offers us. React.memo is identical to the useMemo library and allows us to memoize a component.

import  useCallback, useState  from 'react'
 
 const Button = React.memo((handleClick, name) => 
 console.log(`$name rendered`)
 return name
 )
 
 const Counter = () => 
 console.log('counter rendered')
 const [countOne, setCountOne] = useState(0)
 const [countTwo, setCountTwo] = useState(0)
 const memoizedSetCountOne = useCallback(() => setCountOne(countOne + 1), [countOne)
 const memoizedSetCountTwo = useCallback(() => setCountTwo(countTwo + 1), [countTwo])
 return (
 
 countOne countTwo
 
 
 >
 )
 

If we hit one of them, we'll only see that button to log into the console:

// counter rendered
 
 // button1 rendered
 
 // counter rendered
 
 // button2 rendered

It's because we've applied memoization to the button component and all prop values which are passed to it are interpreted as being equal. The two handleClick functions are stored and are seen as the same function by React until when the values of the item in the array of dependency alters (e.g. countOne, countTwo).


Summary

Although they're cool as useCallback as well as useMemo can be, you must remember they are only useful in certain instances -- so you should not be wrapping all functions using these hooks. If your task is computationally complex, an underlying dependency to another hook or a prop used to memoize a component are good indicators of when you should use useCallback..

We hope this has given you a better understanding of this new feature of React, and that you might have gained confidence in functional programming in the process!

Save time, costs and improve site performance by:

  • 24/7 help and support assistance from WordPress experts in hosting, 24 hours a day.
  • Cloudflare Enterprise integration.
  • The global reach of the audience is enhanced by 29 data centers across the globe.
  • Optimization through our built-in Application for Performance Monitoring.