How to improve performance using memoization in React? [last pt]

Ingryd Moura
hurb.labs
Published in
6 min readAug 16, 2022

If you didn’t read the first part, click here and learn about the memo in React.

In this second part, I’ll talk about when and how to use useMemo and useCallback to enhance performance in your React application.

useMemo and useCallback image.

useMemo

The useMemo is a React hook.

It is a function that returns a memoized value and has a dependencies array.

“So…How does useMemo help us?”

It helps us memoize a value and resolve referential equality.

“Hmmm…Referential equality?”

Yes, in Javascript, there are two equality comparison operators: == for abstract equality and === for strict equality (shallow compare). Referential equality uses strict equality comparison, which returns true if the operators are of the same type and value.

The shallow compare returns true if the values have the same reference.

If you have primitive values like a number or string and the values are the same, return true. But, if you have an object, function, or array, it returns false.

Don’t worry if you don’t understand yet. Let’s go to the example:

  • A simple application renders a fruit in the list by clicking the “Add” button(Line 25 in without_useMemo.jsx)
  • The count function returns the number each time the number “2” appears in my list of fruits(Line 13 in without_useMemo.jsx).

And my Fruit component:

So, we have a count function that doesn’t have useMemo.

When we create a calc or anything in the “body” of this component and React starts the render flow, all this code will be executed even if the result of these functions does not change.

Note that the component is being re-rendered every time a value is entered into the input.

You can see this from the blue border of the React dev tools extension, as seen below:

Giphy of a user typing on input.

In other words, the whole thing is re-rendered and recalculated even if no information has been changed.

If the count function does a much more complex calculation, for example, taking 100000 items and performing some calculation with them, in these cases with useMemo, the calculation will not need to be performed unless any of the variables in the dependency array changes.

Now, with useMemo(Line 16 in with_useMemo.jsx), my code looks like this:

The console.log shows “useMemo” only once!

Image showing useMemo one time on console.

But, If I add fruit, useMemo shows one more time because the fruits state in array dependency changed.

In this giphy, I add two fruits in my application, and useMemo appears one when rendering the app and more two times in the console on the browser.
Giphy is showing useMemo when clicking on add button.

Go to the other example. Suppose I want to pass the count function to the Fruit component(Line 30 in with_useMemo2.jsx).

In a previous post, I explained Profiler from React Dev Tools, and we need to use it here.

So let’s start recording.

In this case, I’ll add other fruits, useMemo will appear as many times as the component Fruit was added, and in the Profiler, you will see that no fruit components are re-rendered.

useMemo with primite value — In this giphy, I add two fruits in my application, and useMemo appears one when rendering the app and more two times in the console on the browser. When writing to the input, no useMemo console.log appears. Next, start recording in the React Dev Tools Profiler, add two more fruits and add one more letter to the input. With this, it will appear that no fruit components have been rendered in the Profiler.
Giphy shows useMemo with primitive value when clicking on the add button and the not rendered Fruit components.

According to the giphy above, this is happening because I am using useMemo, but even if I had not used useMemo, the components would not re-render.

That’s because the count function returns a primitive value (number, string)(Line 16 in without_useMemo.jsx), so the memo’s comparison inside the Fruit component can verify that one is equal to the other.

When we have primitive values, the comparison of === returns true; when it is an object, function, or array, it returns false.

So if the information I had in the count were not a number but an object(Line 21 in with_useMemo2.jsx), the re-rendering would happen.

For example:

Because it has detected that the count property has changed, even though the count hasn’t changed. As React makes this shallow compare, it simply compares if the object reference is the same as the other, and in the case of javascript, this comparison doesn’t go into each of the object’s properties to see if the value has changed.

useMemo with object value — In this giphy, I add three fruits in my application and write three letters on input. Next, start recording in the React Dev Tools Profiler, and all fruit components have been rendered in the Profiler.
Giphy shows useMemo with object value when clicking on add button and the rendered Fruit components.

“I’ll use useMemo in my entire application.”

Giphy of a cat shaking its head negatively

No guys!

So…when should I use it?

  • Complex calculations
  • Solve referential equality problems

useCallback

The useCallback is a React hook.

It is a function that returns a memoized callback and has a dependencies array.

“So…How does useCallback help us?”

It helps us memoize a function and solve referential equality problems.

Let’s go to the example:

In this case, we have a favorite state fruit and a function that adds a new fruit to this list (Line 14 in with_useCallback.jsx). A prop passes this function to the Fruit component (Line 36 in with_useCallback.jsx).

In the Fruit component, we have the prop onAddFavoriteFruit and a button to add the fruit to the favorites list.

We will add fruit to the application and write something in the input.
I start recording using the Profiler, add one more letter and stop recording.

Without useCallback — In this giphy, three fruits are added in my application and three letters in my input. Next, start recording in the React Dev Tools Profiler and add one more letter on input, and all fruit components have been rendered.
Giphy shows the example without useCallback when clicking on add button, adding letters on input, and all fruit components have been rendered.

Notice that all the fruit components have changed; they have entered the rendering flow because the onAddFavoriteFruit property has changed.

When a function is created within the App component, every time that component renders, that function will be recreated in memory, i.e., when I write to the input, that function is recreated and will occupy a new memory position.

When javascript compares whether one function is equal to another, it checks to see if both functions occupy the same memory position.

In this case, even when the memo in the Fruit component compares the previous props with the new property, it uses the shallow compare algorithm. It tries to check if this function is different from the previous one.
As this function occupies a different memory position than the previous one, and since it is being recreated every time the state is updated, it will understand that this component needs to render again. I mentioned referential equality when we check if a variable or function is equal to another based on its memory reference.

So to solve the problem, we add a useCallback(Line 19 in with_useCallback.jsx) around the addFavoriteFruit function. The useCallback allows us to store a function in a memory location so that when that component renders, we don’t have to recreate that function.

My Fruit component is the same.

Like useMemo, useCallback has an array of dependencies. In this case, for the addFavoriteFruit function, we add favoriteFruit as a dependency(Line 27 in with_useCallback.jsx).

If we test now and add some fruit, save, write to the input and stop saving, you will see that none of the Fruit components are re-rendered.

With useCallback — In this giphy, three fruits are added in my application and three letters in my input. Next, start recording in the React Dev Tools Profiler and add one more letter on input; all fruit components have not been rendered.
Giphy shows the example with useCallback when clicking on add button, adding input values, all fruit components have not been rendered.

When should I use it?

  • Solve referential equality problems.

The useCallback is not a hook to be used when a function has a lot of code inside; it will not make a function load faster; it will only prevent that function from being recreated each time it is rendered.

“So can I use useCallback for everything?”
-
As I said to the others above, Nooop! 😬

When a function is accessed only by the component that creates it; in most cases, useCallback will be more expensive than React by recreating that function each time it is rendered. For example, a simple function used only by that component itself, without being passed to another child component, or a function that is not within a context.

So only use useCallback if the function is being passed to other components or is a function in a context where more than one component accesses the same function.

I hope you understand how and when to use useMemo and useCallback React hooks in your applications and improve the performance of your projects!

See you later!

Giphy of a cat going away.

--

--