React useCallback and useMemo Hook

WebTechRiser.com > Javascript > React useCallback and useMemo Hook

As we know, React.js is a component-oriented JavaScript library. And we also know that when a component in React.js changes the value of a state, the whole component and the child components in it are rendered at once.

Many will say, where is the problem here? There is a problem here.

When we work on a small project where only a few components are used, the problems are not well understood. But, when we work on a big project, we see that as the project gets bigger, the speed of the program decreases and the load increases. However, we use React to make our program run smoothly and fast.

Well, imagine that 15 child components are implemented inside the “App” component of your project, and every time the “App” component is rendered, the remaining 15 child components are rendered all at once. If it takes 0.3 seconds for one component to render, then how long does it take for all the components to render ?!

Now I hope you understand why the pace of your program slows down as the project gets bigger. It’s a matter of concern, isn’t it?

Now how can this be solved? Yes, like all problems there is a solution.

I hope, by the end of the article you will get a nice solution to this matter.

Let’s start with an example below:

import React, { useState } from "react";
// Components
const IncreaseCount = (props) => {
    console.log("Button -> Count");
    return (<button onClick={props.onIncrementCount}>Increase Count</button>);
};
const IncreaseAge = (props) => {
    console.log("Button -> Age");
    return <button onClick={props.onIncrementAge}>Increase Age</button>;
};
const Title = (props) => {
    console.log(`Title -> ${props.title}`);
    return <h1>{props.title}</h1>;
};
//Main Component
function App() {
    //States
    const [count, setCount] = useState(0);
    const [age, setAge] = useState(0);
//Functions
    const handleIncrementCount = () => {
        setCount(count + 1);
    };
    const handleIncrementAge = () => {
        setAge(age + 1);
    };
    return (
        <div className="App">
        <Title title="Count" />
        <h2>{count}</h2>
        <IncreaseCount onIncrementCount={handleIncrementCount} />
        <Title title="Age" />
        <h2>{age}</h2>
        <IncreaseAge onIncrementAge={handleIncrementAge} />
        </div>
    );
}
export default App;

If I look at the codes above, I can see, here:

  • First a parent component called App has been created on line 18.
  • 2 states have been defined as count and age.
  • 2 functions called handleIncrementCount and handleIncrementAge have been created whose job is to increase the value of count and age by 1.
  • IncreaseCount and IncreaseAge have been made up of two components up to lines 3-10, each of which has a button and each button has an onClick event whose job is to call the functions when the buttons are clicked.
  • A component called Title has been created for lines 11 – 14, whose job is to print titles.
  • Again, console.log has been defined one by one in IncreaseCount, IncreaseAge and Title components. So, every time these components are rendered, they will print a message on the browser console.

So, let’s see what happens after running this program:

If we look at the program, we can see that after clicking on any of the buttons, all the child components in the “App” component are being rendered. But, we didn’t want that. We only want to render all the components related to the one whose value will be updated.

How can this be solved? Let’s discuss the reasons for rendering a child component as needed before starting the solution.

Unnecessary reasons: It, when a component is rendered, renders all the components in it. It renders the child component unnecessarily.
Reason required: It renders the child component when the value of any property of the child component changes.

Examples will be given below when solving.

Now let us solve this problem. To solve this we will use a function called “memo“. The function of this function is to block all unnecessary renders.

import React, { useState, memo } from "react";
// Components
const IncreaseCount = memo((props) => {
    console.log("Button -> Count");
    return <button onClick={props.onIncrementCount}>Increase  Count</button>;
});
const IncreaseAge = memo((props) => {
    console.log("Button -> Age");
    return <button onClick={props.onIncrementAge}>Increase Age</button>;
});
const Title = memo((props) => {
    console.log(`Title -> ${props.title}`);
    return <h1>{props.title}</h1>;
});

To use “memo” in a basic syntax function, you can follow the following rules:

function Title(props){
    console.log(`Title -> ${props.title}`);
    return <h1>{props.title}</h1>;
};
Title = memo(Title);

Let’s run the program now:

react-usecallback-usememo-hooh-2

If we look at the image above, we see that the program rendered all the components only once during the run, i.e. during the first render. But when a button is clicked, only 2 components are running. Although our problem is not completely solved, it is still somewhat solved. If we take a closer look, we see that the “Title” component is no longer being rendered.

As we can see, we have created a property called “title” in the “Title” component, with “Count” value in one and “Age” value in the other, which was not updated every time. The “Title” component was still being rendered. So, since it had no reason to render, its render was an example of an “unnecessary reason”. Also, the function of the “memo” function is to stop the execution of unnecessary renders.

Well, now let’s find out why the other button is being rendered after clicking on one button.

We know that when a program is run again, everything in it is rebuilt and their memory location changes.

Similarly, every time rendering is done in React component, the functions in it are created anew. As a result, whenever the value of the state is being rendered due to an update, all the functions are being re-created and its memory location is being changed and new references are being received.

In most cases we pass the reference of the function to the component of “react”. For example, onIncrementAge = {handleIncrementAge}. Here, onIncrementAge is the property and handleIncrementAge is the reference.

Each time a render is made, the references to the new function are re-created. All the references are re-rendered to the child component where the functions have been passed. So this is an example of being rendered for “necessary reasons”.

Now we know that every time a component is rendered, the function in it and its reference are created anew and the components related to it are rendered to update its reference location.

useCallback Hook

Now if the functions of the parent component are not newly created in each render, then there will be no need to render any component related to it. To solve this problem, “React” has a hook called useCallback.

useCallback(function, [dependency])

The function of the useCallback hook is that it caches all the functions used in the previous render and checks the value of the properties in its dependency each time it is rendered. Creates a new function only if the value changes. And if the value does not change, it brings the function in the cache.

Now let’s apply this function to our program and see how it affects our project:

//Functions
const handleIncrementCount = useCallback(() => {
    setCount(count + 1);
},[count]);
const handleIncrementAge = useCallback(() => {
    setAge(age + 1);
},[age]);

If we notice the code, first we pass a function in the first argument of the useCallback function and we pass a dependency in the second argument. You can give more than one dependency if you want, there is no problem. The functions are being created anew whenever the dependencies are being updated.

Now if we run our program, what will we see?

react-usecallback-usememo-hooh-3

useMemo

The useCallback and useMemo hooks work exactly the same, but with some differences. The useMemo hook works the same way the useCallback hook works, but the difference is that the useCallback hook returns a “function” and we get a “value” from the useMemo hook.

With an example we will see how it works.

import React, { useState, useMemo, useCallback } from "react";
const App = () => {
//States
const [count, setCount] = useState(0);

//Functions
const func1 = useCallback(() => {
  let a = count * 10;
}, [count]);
const func2 = useMemo(() => {
  let a = count * 10;
}, [count]);

console.log(func1);
console.log(func2);

return (
    <>
      <button onClick={() => setCount(count + 1)}>Count: {count}</button>
    </>
  );
};

export default App;

If we look at the codes of the above program, we will see that two variables up to lines 8-13 have been created here, in which two similar functions, one useCallback and the other using useMemo are placed in func1 and func2 respectively and these are 15 And printed on line 16 through console.log.

Now if we run this program:

react-usecallback-usememo-hooh-4

As can be seen in the image above, every time we click on the buttons, console.log prints 2 values. The first is a “function” and the other is “undefined”.

What is the reason for this?

I said at the beginning that the useCallback hook returns “function” and the useMemo hook returns “value”. This means that when you pass a “function” in useCallback, it will return that “function” to you based on its dependency. However, when you pass the “function” in useMemo, it will return the “return value” of the function.

Since we have not returned any value to the useMemo function here, it is returning us “undefined”.

Now, let us return to its function:

const func2 = useMemo(() => {
    let a = count * 10;
    return a; 
}, [count]);

Now, let’s run our project again:

react-usecallback-usememo-hooh-5

Notice now that console.log is no longer printing “undefined”.

Wrapping Up

By this time I have reached the end of my article. Here is a summary of what I have discussed in this article:

  • How render works in React.js and some of its problems.
  • Reasons to render components.
  • Ways to protect child components from “unnecessary renders”.
  • Ways to protect child components from “required render”.
  • Familiarity with useCallback and useMemo hooks and their use.

Many thanks to those who read this long article of mine and came to the end of it. One last thing, many people are confused about which of useCallback or useMemo hook is better to use. I think it’s best to use useCallback in all other places, not just where you don’t use useMemo.

Category Javascript
Tag:

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.