This article is originally written here along with the code images -> https://easyontheweb.com/usememo-and-usecallback-with-example-in-react/
Memoization is one of the best and most efficient techniques you can use as a developer. I absolutely love hashes as a data structure and love to make use of them. In this article, we’ll see how we use memoization hooks like useMemo and useCallback with an example each in React.
First of all, if you are unaware of memoization you can think of it as storing the value for a particular argument and then rather than re-calculating the value when the same argument comes again, we pick the up memoized value from where we have stored it.
Memoization in React
So, hopefully now you know what memoization actually means. So, let us think of it in React’s world now. One of the major things about React is that it re-renders the DOM whenever a piece of state or a piece of props changes. What also happens is that all the subcomponents of that component re-render too when the state/props of the parent component changes.
A small issue with this is that consider the parent component has a prop called “name” and another prop called “age”. Let there also be a child component for this component that takes the prop of “age”. Now, consider this – if the prop called “name” changes for the parent, the parent re-renders right? That everyone knows, but the issue is that the child would also re-render even though it has no dependency on the “name” prop.
In an ideal world, we only want. the child component to re-render if the “age” prop has changed in the parent.
In order to achieve this, we have something called React.memo. It is a higher order function that wraps your functional component and makes sure that the component will re-render only if it’s props or it’s own state is changed. Wrapping the component with React.memo means that the component will not be re-rendered due to a change in the parent’s props or state.
As you can imagine, this is a good thing most of the times. What you have to remember though is that React.memo only does a shallow comparison of the props it receives. You can also pass a second argument (a function) to compare the props in your way though. Check the docs for that.
React.memo in use
Simple, right? I hope what React.memo does is clear to you now.
Let us see what useCallback is and how we can use it to enable is to continue take benefit of the React.memo higher order function.
As I told earlier, the React.memo only does a shallow comparison of the props it receives. This becomes an issue when suppose the prop being received is a function. Why? Let’s see.
This is just a simple component with a piece of state called count and a function that basically just increases the count. This function is passed as props to a child component called increment.
Here, in the child component you see that we console log the render no. , i.e, how many times has the component rendered. You also see that we’ve used the React.memo wrapper here, so ideally this component would only re-render when it’s props (here we have just a single prop called increment) change. If you run this application and click the increment button present here, you’ll see that the child component re-renders on every click.
Why is that? That is because the increment function of the parent is getting created again and again on every re-render of the parent. Now, as functions are stored by reference in JS, this means an entirely new function is created at an entirely new memory location. Therefore, React.memo is comparing the two functions and seeing them different, therefore, re-rendering the child as well.
This is where the useCallback hook comes into help.
useCallback example in React
The only difference in this and the last App component is the use of the useCallback hook. What this hook does is somewhat similar to the useEffect hook, it has an array of dependencies and it will only be called when one of those dependencies changes. It also returns a function obviously. So, what is happening here is that the increment function is getting created with the help of the useCallback hook.
This increment is being passed down as props, but the difference is that this time the same increment function is being passed down even when the parent component re-renders. Therefore, the React.memo sees that the props have not changed and therefore there is no need to re-render the child component. Pretty neat, eh?
useMemo is a very close relative of the useCallback function and what it does it basically memoize a value for a given argument. This is particularly helpful when we do not want to do some heavy calculation on every re-render of a component (when the calculation does not depend upon the prop/state changed).
Let us assume our component makes an API call that returns us an array of numbers , now we want to calculate the largest of those numbers and display it. Something along the lines of this…
So, what we’re doing here is assuming that we are getting a data array (also, now that I see it, ignore my console log there please 😛 ) and setting the data state with that array. We are calculating the largest number in the function called findLargestNum, nothing special so far but what the problem is that even when we change the count state, the entire component will get re-rendered and the findLargestSum will get called again (which will be seen in the console log).
The problem is that changing of count has nothing to do with the re-calculation of the largest number, does it? Therefore, we can optimise such a situation using the useMemo hook.
Let us see with this useMemo example.
useMemo example in React
Let us now understand what this new code does. Well, as you see we are using the useMemo hook here, the useMemo hook takes a function as the first argument, where we have given the findLargestNum as a part of the lambda. The second argument it takes is an array of dependencies. As we know that the largestNum will only depend on the data and findLargestSum function itself, we pass those two as dependencies.
Another change that we have made here is move the findLargestNum function outside the component. Why? Because if it was inside the component it would be created again and again on every render and thus there would be no use of the useMemo as one of it’s dependencies would be changing. Another way to handle this would’ve been to use useCallback but I’ll leave that for you to explore.
Now, when any part of the props or state changes, we do not recalculate the largestNumber, which is what we wanted.
A very important thing to note with useMemo is that you should only use it when the computation is significant and you are able to see a lag or something while interacting with the page, otherwise it will not be of much significance.
So that is it guys, we just saw the use of useMemo and useCallback with an example each in React.
If you want to learn more about these two hooks, please checkout a great channel by Ben Awad -> https://www.youtube.com/channel/UC-8QAzbLcRglXeN_MY9blyw