loading...
Cover image for Demystifying React Hooks: useCallback and useMemo

Demystifying React Hooks: useCallback and useMemo

milu_franz profile image Milu Updated on ・3 min read

React Hooks introduced the capability to use state and other lifecycle features while using functional components instead of classes. Hooks are a simpler way to encapsulate stateful behavior and side effects in a user interface while using less code and increasing readability.

Some hooks are easier to understand and use than others, therefore this series of posts will focus on demystifying the hooks that are not as straightforward. Let’s start by explaining what occurs when a component re-renders, followed by defining the purpose of useCallback and useMemo, and finally discussing when it is and when it is not appropriate to use these hooks.

What occurs when a component re-renders?

As you might already know, React re-renders components on every state change or when props change. Since functions are considered objects in JavaScript, all objects (including functions) created under a React functional component will be created again on every re-render. This occurs as a consequence of referential equality, which means that two objects that look exactly alike are not the same unless they both point at the same object.

Alt Text

In other words, when a React component is about to re-render, it compares each object created under its original component with the new version of itself. And even though the objects are exactly the same, they are not pointing at the same object, therefore React identifies them as different objects and it allows their re-creation all over again under each re-render.

What is the purpose of useCallback and useMemo?

The purpose of useCallback and useMemo, if used correctly, is to prevent unnecessary re-renders and make your code more efficient.

Let’s take a look at their structure. Both of these hooks receive two parameters:

1) a function
2) an array of dependencies

Alt Text

useCallback hook returns the same instance of the function being passed (parameter #1) instead of creating a new one every time a component re-renders.

It creates a new instance of the function being passed (parameter #1) only when the array of dependencies (parameter #2) changes.

Let’s look at an example, here we have a simple app that adds two values. The user can increment the first value and/or decrease the second value and the result will update accordingly. We also have a third extra value that the user can update, however, this number is not being used in the computation.

If the user interacts with the extra state value, the component would re-render creating a new copy of the additionResult function even though extraVal is not used in it. In this example, we implement the useCallback hook to only create a new copy of the additionResult function if firstVal or secondVal are updated.

Alt Text

useMemo hook is very similar, however, instead of returning an uncalled function as useCallback does, it calls the function being passed and only returns a result value when the array of parameters change. In other words, useMemo calls the passed function only when necessary and it returns a cached value on all the other renders.

In this example, we implemented an app that accepts a number and it returns it's factorial. For instance, if we typed the number 5, it would use a recursive function to compute 5!= 5*4*3*2*1=120. In this case, we used the useMemo hook to tell React to only recalculate when the number changes.

When to use them?

If you are thinking of adding useCallback and useMemo hooks everywhere in your component, please don’t.

Both of these hooks add some extra complexity to your code and they require a lot of things working under the hood.

Adding performance optimizations using useCallback and useMemo is expensive and these optimizations don’t always bring enough benefits to offset their cost.

You should consider using useCallback and/or useMemo hooks on the following situations:

1) Processing large amounts of data
2) Working with interactive graphs and charts
3) Implementing animations
4) Incorporating component lazy loading (useMemo specifically)

Summary

When a component is re-rendered, it creates new instances of all objects, including all the functions in it.

useCallback - Allows you to cache an instance of a function between renders.

useMemo - Allows you to cache a value between renders.


I hope you found this post helpful and that you will start using useCallback and useMemo with confidence in your next project.

I post new content every week. We will be exploring a different React hook next Sunday!

Posted on by:

milu_franz profile

Milu

@milu_franz

Software Engineer, co-founder of @imagine_dat_dyt and mother of mutts.

Discussion

pic
Editor guide
 

Nice stuff!
Where did you made those thumbnails and pictures?
If any website, do share!

 

Thank you! I drew the illustrations using an app called Paper Pro :)

 

Thank you! I like those illustrations!
I will use it on my youtube videos!
😅😅😅

The app is super easy to use and it has a free version as well. Definitely very useful to draw quickly!

Generally, I use to make some sketch like designs by excalidraw application...
Now, I find some new tech.

 

Thanks for the article. The illustrations make it easy to follow.

useCallback hook returns the same instance of the function being passed instead of creating a new one when a component re-renders. This occurs only when the dependencies passed to the second parameter change.

I think the above statement is a little confusing. What occurs when the deps change? Is it:

  • Returning the same instance of the callback?
  • Creating a new instance of the callback?
 

Hi Joseph! Thanks for your question... I can see how this statement is confusing.

Let’s take a look at useCallback’s structure. It receives two parameters:

(#1) a function
(#2) an array of dependencies

useCallback returns the same instance of the function being passed (parameter #1) instead of creating a new one every time a component re-renders.

It creates a new instance of the function being passed (parameter #1) only when the array of dependencies (parameter #2) changes.

Does this make sense? I will update my post to make sure this definition is more clear. Thanks for your feedback :)

 

Thanks for the feedback. I think it will be clearer when you update it.

 

Great article.

Adding performance optimizations using useCallback and useMemo is expensive

Wouldn't you mind to tell where can I read more about it? I saw some notes in official docs about using these only as performance optimization, but have never read any post or explanation from someone from core team or seen some benchmarks. Thanks!

 

Hi Ramil, thank you for reading! Let's break down some reasons why useCallback and useMemo are expensive:

Regular function: const testFunc = () => { ... do something }

useCallback: const testCallbackFunc = useCallback(() => { ... do something }, [dependencies]);

In the callback example, you are creating your regular function + calling a callback + passing an array of dependencies. It is already a bit more complex when looking at them side by side, but also the useCallback hook is setting properties and running through its own logic under the hood. So, if you are trying to optimize something super simple like the regular function I have in my example, useCallback and useMemo are just not worth it. We are creating complex code for ourselves and requesting our component to run other complex logic under the hood to optimize something very minimal.

Here is a fantastic article by Kent C Dodds that explains this in more detail.

I hope this explanation was helpful :)

 

Thanks Milu for another informative post.
Keep the good work continue.

But, one Question please -
What are the alternatives of these 2 functions please? because you have said in your post these both functions add performance optimizations and expensive.

 

Glad you found this post helpful and thanks for reading! :)

 

Thx for sharing !

 

No problem Nuno! I will be exploring a few other React hooks in the next couple weeks :)

 

Great article! I often see examples, where the submit function of a form is wrapped in a useCallback, but I dont see the reason why someone would do that, any idea?

 

Hello there! The only reason I can think of is that whoever is implementing the code, does not want their handleFormSubmit() function to be created every time the component re-renders. I found this article where they use the useCallback() hook in a handleFormSubmit() to stop tree invalidation issues. However, I haven't encountered issues when creating a form without using useCallback in the past.

 

Damn. I wish I'd read this before my most recent interview lol. Thank you, Milu!

 

oh no! Now you are ready to conquer the next one though. Thanks for reading :)

 
 

No problem Patricio :) thanks for reading!

 

Hey, Milu! Amazing article and writing style! Can I translate it to Portuguese (Giving you the proper reference)?

 

Hi Rodolpho, yes you can translate it to Portuguese. Send me the link when its ready :)

 

Thanks. Milu
What would be the next post about?
I look forward to your next one
Thanks again

 

Hi there! I'm thinking to explore useRef next but I'm open for suggestions. Thank you for reading! :)

 

Very clear explanation, thanks for sharing!

 

Thanks Alberto! :)

 

Love the little illustrations!

 

Thanks Bennett!