Detailed explanation on useMemo Hook in React.

Detailed explanation on useMemo Hook in React.

In this blog, I will explain you about useMemo hook. Before jumping to it firstly let's know what is hooks?

HOOKS

Hooks are the new feature introduced in the React 16.8 version. We know in class component we need to write class to use State and other lifecycle methods. But hooks which can only be used in function component provide us the way to directly use class and other lifecycle features without actually writing the class. In simple these has made our life easier.

See the below code to know the difference between writing state to use in class component and functional component.

Below is the code for counter app that will increase the number of counts as users click on the “Add” button using Functional and Class components.

Using Class Component:

import React, { Component } from "react";

class ClassComponent extends React.Component{
    constructor(){
        super();
        this.state={
            count :0
        };
        this.increase=this.increase.bind(this);
    }

   increase(){
       this.setState({count : this.state.count +1});
   }

    render(){
        return (
               <h2> {this.state.count}</h2>  
               <button onClick={this.increase}> Add</button>

            </div>
        )
    }
}

Class Components is the bread and butter of most modern web apps built in ReactJS. These components are simple classes (made up of multiple functions that add functionality to the application).

See below the same code written using useState hook with functional components. (hook to manage state) .

Using Function Component :

import React, { useState } from "react";

const FunctionalComponent=()=>{
    const [count, setCount] = useState(0);

    const increase = () => {
        setCount(count+1);
    }
   return (
        <div>
          <h2>{count}</h2>
            <button onClick={increase}>Add</button>
        </div>
    )
}  
export default FunctionalComponent;

Functional components are some of the more common components that will come across while working in React. These are simply JavaScript functions. We can create a functional component to React by writing a JavaScript function.

So now I think you are familiar with class and functional components. and how hooks in functional component have simpler code that implements similar functionalities faster and more effectively.

So now Lets jump into useMemo Hook.

useMemo Hook

The React useMemo Hook returns a memoized value. Think of memoization as caching a value so that it does not need to be recalculated. The useMemo Hook can be used to keep expensive, resource intensive functions from needlessly running.

Take a example below, we have a code which has two states, number (for managing the number value) and a dark which has a boolean (for managing the theme), and a function double number which doubles our number, but this function is very slow as it has a long loop which do nothing for a really long time all this do is making our function slow, so it basically take a second and half to double a number. Also, we have a variable themeStyle which changes the background color on the basis of boolean in dark, If boolean is true the background color is black and text is white and vice versa. and inside return we have our output code which has an input to change the number value and a button to toggle theme and finally a div which shows the value of number with the styles present in themeStyle.

import React,{useState} from "react"
export default function App(){
const [number,setNumber]=useState(0)
const [dark,setDark]=useState(false)
const doubleNumber = slowFunction(number)
const themeStyle = {
backgroundColor: dak ?'black":"white",
color:dark?'"white'":'"black'"
}
return (
<div>
<input  type="number" value={number} onChange={e=>setNumber(parseInt(e.target.value))}></input>
<button onClick={()=>setDark(prevDark=>!prevDark)}>Change Theme</button>
<div style={themeStyles}>{doubleNumber}</div>
</div>
)
}
function slowFunction(num){
for(let i = 0; i<=10000000;i++){}
return num*2
}

So this is our code and you may think this is fine and working good, but when you will run this code and give a value to a number it will take a half and a minute to display a value which is okay according to our code but when you will change the boolean in dark you will see that still the code is taking a second or half to display the value, even without changing the value in input, This is how react works it re-render the entire component once you update any state, which means the slow function will be called every and each time when we render our App component whether we are updating the number or any other component causing the App to re-render which means the slow function will run, which is a big performance issue as it will make our App really slow.

So don't worry, React has a built in hook useMemo to solve these kinds of issues here memo stands for memoziation which is basically caching a value. It takes a function and a dependency similar to useEffect hook ie, it will execute its body which has a function only when its dependency changes.

Now we will keep this slowFunction inside a useMemo and will give a dependency number, so now the slowFunction will run only when the value of number will update. Since we know the slow function takes a number as argument and will give the same output for same input,so using useMemo we are caching the number value. ie on every render the number value will be cached and useMemo will execute only when the number value will be different from last cached value, ie it will compare the cached value and present value. Below is the code which is the modified version of above code , In this I have used useMemo.

import React,{useState,useMemo} from "react"
export default function App(){
const [number,setNumber]=useState(0)
const [dark,setDark]=useState(false)
const doubleNumber = useMemo(()=>{
slowFunction(number)
},[number])
const themeStyle = {
backgroundColor: dak ?'black":"white",
color:dark?'"white'":'"black'"
}
return (
<div>
<input  type="number" value={number} onChange={e=>setNumber(parseInt(e.target.value))}></input>
<button onClick={()=>setDark(prevDark=>!prevDark)}>Change Theme</button>
<div style={themeStyles}>{doubleNumber}</div>
</div>
)
}
function slowFunction(num){
for(let i = 0; i<=10000000;i++){}
return num*2
}

So now when we update any state or take a dark state when we update it the slow function will not be called, it will be called only when the number value will be changed. So we are saving ourselves from recalculating the number values unnecessarily and running slowFunction. Now our App will work fine.

Now the second usecase of useMemo is in Reference Equality. We know in javaScript we compare two object and array on based of their reference.

For example ,

const obj1 = {
name:"john"
}
const obj2 = {
name:"john"
}

You may think these both are same as they have same value but In javaScript these reference to different object so these both are not equal.

Now suppose we want to console a string "theme changes" everytime our themeStyle changes . ie,

import React,{useState,useMemo,useEffect} from "react"
export default function App(){
const [number,setNumber]=useState(0)
const [dark,setDark]=useState(false)
const doubleNumber = useMemo(()=>{
slowFunction(number)
},[number])
useEffect(()=>{
console.log("Theme Changed")
},[themeStyle])
const themeStyle = {
backgroundColor: dak ?'black":"white",
color:dark?'"white'":'"black'"
}
return (
<div>
<input  type="number" value={number} onChange={e=>setNumber(parseInt(e.target.value))}></input>
<button onClick={()=>setDark(prevDark=>!prevDark)}>Change Theme</button>
<div style={themeStyles}>{doubleNumber}</div>
</div>
)
}
function slowFunction(num){
for(let i = 0; i<=10000000;i++){}
return num*2
}

but on running the code you will see that the console will print even when we change only the number not the dark state . This is because on every render a different themeStyle object will be created which inspite of having same value will have different reference and thus the present themeStyle object will not be equal to the present themeStyle which is created after render. So in order to solve this issue we will use useMemo. See the below code in which themeStyle object is getting value only when the dark state is actually changing.

import React,{useState,useMemo} from "react"
export default function App(){
const [number,setNumber]=useState(0)
const [dark,setDark]=useState(false)
const doubleNumber = useMemo(()=>{
slowFunction(number)
},[number])
const themeStyle = useMemo(()=>{
return (backgroundColor: dak ?'black":"white",
color:dark?'"white'":'"black'"
)
})
return (
<div>
<input  type="number" value={number} onChange={e=>setNumber(parseInt(e.target.value))}></input>
<button onClick={()=>setDark(prevDark=>!prevDark)}>Change Theme</button>
<div style={themeStyles}>{doubleNumber}</div>
</div>
)
}
function slowFunction(num){
for(let i = 0; i<=10000000;i++){}
return num*2
}

So it seems great and you may think why can't I use useMemo everywhere and memoize every value. You should not because it will give performace overhead and some memory overhead as you will save this cached value in some memory location and using useMemo on unnecessarily place you are going to save its value and increasing memory, which is not at all a good thing. So use useMemo when you actually need it. Please write the code and see the results in console to understand its flow better.

That's it for now! Please drop your thoughts in the comments. Happy coding. https://twitter.com/ShrinkhlaR Reference - https://reactjs.org/docs/hooks-reference.html#usememo