React — memo & useCallback hook to handle the re-evaluation issue!!

Rajesh Kumar
6 min readApr 10, 2022
Photo by Lewis Kang'ethe Ngugi on Unsplash

In this article, you will see how we can deal with the problem caused by re-evaluation in ReactJs.

If you have not read out my previous article on React — re-render vs re-evaluation issues with ease!! . Please read out it first then only you will be clearly understood why, how, and when should you use React memo and callback!!💻

In my previous article, you learned that if you don’t handle re-evaluation properly there will be unnecessary re-execution and function re-creation and this will lead to unwanted bugs or performance issue in the application resulting in a bad user experience.

Let’s recall the same react application and code from the previous article !!

NOTE :- I am just focusing on functional component and not the class component.

Preventing Unnecessary re-evaluation with React memo

Let’s use the concept of React memo to handle unnecessary re-evaluation of the child component <Greeting/> due to props showMsg={true}.

So now you want to re-evaluate the Greeting component only when the value of showMsg props will change. i.e true →false or false →True .

To achieve that for primitive values we can use React.memo() in Greeting component like below:-

import React from "react";const Greeting = (props) => {console.log("Greeting Components");return <>{props.showMsg && <p>Welcome to XYZ pvt. Ltd.</p>}</>;};export default React.memo(Greeting);

Through this, you tell react to re-evaluate the <Greeting/> component only when any props value changes. In this case for Greeting, there is only one prop data i.e showMsg . So whenever the previous props value of showMsg changes ReactDOM will re-evaluate the <Greeting/>component.

You can verify in the browser console that only the <App/> and <Button/> components will print the console message when you click the Show/Hide message button.

So now you are thinking that you can use React.memo() directly inside each component to prevent this unnecessary re-evaluation and to optimize the application. 😀

But that’s not true we should avoid unnecessary use of React.memo()inside each component of an application to handle all re-evaluation. Because React.memo optimization also comes with a cost.

This memo() method tells React that whenever there is a change in the App component go to the child component Greeting and compare all the previous values of props with the new value of props.

So React has to do 2 things:

  • Store all the previous props values.
  • Then it needs to do the comparison with previous and new props values.

And both of these works have their own performance cost. So you should just analyze yourself and decide when it is worth using React memo or not.

The general approach to decide that, if the number of nested child components is very small or the lines of code are few and re-evaluation of those components is not going to cause too many problems to the application and user experience then there is no need to implement memo() . But if the number of nested child components is more or the number of code lines or complexity is more then in that case you should use memo() .

As you have already learned in my previous article, you can’t handle the component <Button/> usingReact.memo() because it is using only props which are of type function i.e toggleHandle={toggleMsg} and in every execution, the function creates a new reference that is not the same as the previous props value because, in Javascript, a function is nothing but an object.

To handle the function re-creation we can use the concept of useCallback

Preventing Unnecessary function re-creation with React useCallback

It’s a React hook that provides the feature to handle unnecessary re-creation of function(which is nothing but Reference type i.e object).

So let’s understand the concept that useCallback use to handle unnecessary function re-creation. To understand it let’s take an example to reference type. Suppose you have two objects which similar to the below:-

const obj1 = {};
const obj2 = {};
obj1 === obj2 // false

Both objects look like same and have empty objects as values but if we will compare these two it will return false because as we know in Javascript two different reference variables are not the same. In this case obj1 & obj2 point to the two different locations of empty objects which means it stores the empty object value in different locations of heap memory that’s why these two are different.

But suppose you will write the above code something like the below:

const obj1 = {};
const obj2 = obj2;
obj1 === obj2 // true

In this case, both obj1 & obj2 are the same because it’s two different reference variables but they point to the same address.

A similar concept is implemented with the useCallback. It stores the initial function creation somewhere in memory, and whenever again the same function calls it uses the same reference. So that way the same function will not be re-created again.

Syntax of useCallback:

useCallback( fun, [ dependencies ])

useCallback takes a function as the first parameter that you do not want to re-create un-necessarily and the second parameter is the array of dependencies that are used to inform useCallback to create a new function if the dependencies value change.

If you will pass an empty array [] as dependencies that means that function inside useCallback will create only once because there are no array dependencies and as useCallback only re-create the same function when the value of any dependencies changes.

If you will add other dependencies then a change in the value of added dependencies only will lead to creating a new instance of the same function.

I will cover about different dependencies of React hooks in more detail in other articles.

Now it’s time to implement the concept of useCallback in the sample react app of <App/> component, where we want to avoid the unnecessary toggleMsg function re-creation, which resulted in unnecessary re-evaluation of the child component <Button/>.

import React, { useState, useCallback } from "react";
import Greeting from "./Greeting";
import Button from "./Button";
export const App = () => {
console.log("App Component");
const [show, setShow] = useState(false); const toggleMsg = useCallback(() => {
setShow(!show);
},[]);
return (
<>
<h1>Hi John</h1>
<Greeting showMsg={true} />
<Button toggleHandler={toggleMsg}>Show/Hide Msg</Button>
</>
);
};

In this case, useCallback stores the instance of the toggleMsg function when you will click on Show/Hide Msg the first time and when you will click next time it will not create the new instance instead of that it will use the same reference.

In this case, when you will click the button Show/Hide msg for the first time, the useCallback stores the instance of the function toggleMsg , and when you click next time it will not create a new instance, instead, it will use the same context.

You can verify in the browser console that after the first click it will not re-evaluate the component <Greeting/> and Only the <App/> component’s console message will be printed.

Like React.memo(), it also has performance costs so we have to follow the same rule of memo for using useCallback as mentioned above in the memo section.

That’s how we can handle the unnecessary re-evaluation flow in react using memo and useCallback methods .😃

I hope all of your concepts have been cleared!!! If you really liked this article click the clap 👏 button below. Also, write your feedback and queries in the comment section.✍

--

--