How to implement Memoization in React and vanilla JS

Posted By :Aadarsh Pathak |30th July 2022

Memoization in JS:

A simple JS implementation for Memoization would be as follows :

Without Memoization:

const expensiveFunction = (num) => {
  console.log('recalculation done');
  for (let i = 0; i < 100000; i++) { }
  return num + 2;
}

expensiveFunction(2)   // prints recalculation done
expensiveFunction(2)   // prints recalculation done
 

Output : 

recalculation done
recalculation done

With Memoization:

const cache = {};
const expensiveFunction = (num) => {

  const givenArg = JSON.stringify(num)
  if (cache[givenArg]) {
    return cache[givenArg]
  }
  else {
    console.log('recalculation done');
    for (let i = 0; i < 100000; i++) { }
    cache[num] = num + 2
    return num + 2;
  }
};

expensiveFunction(2) // prints recalculation done
expensiveFunction(2) // does not print anything since else part is not executed
 

Memoization in React

  • We have seen how memoization helps when there are expensive calculations to be made
  • In the case of React the expensive operation with which memorization helps the most is the re-rendering of components.
  • First we have to know that React components re-render whenever there is a change in their state or props
  • Additionally , when the parent re-renders then so does the child component irrespective of whether its props or state were changed and when this happens in a fairly large project then performance suffers to tackle this issue we use memorization and it can be achieved using three APIs:

 -  React.memo()
 -  useMemo()
 -  useCallback()


Using React.memo() for Memoization:

React.memo() is a higher order component (HOC) that returns a new component only if the props of the component with which we have called it are changed. This way the child component will no longer re-render even if the parents component does.

Using React.memo()

//  ParentComponent.jsx
import { useState } from 'react';
import MemoChildComponent from './ChildComponent';

const ParentComponent = () => {
  const [counter, setCounter] = useState(0);
  const name = 'poornima';
  const clickHandler = () => {
    setCounter((prev) => prev + 1);
  };
  return (
    <>
      <p>{counter}</p>
      <button onClick={clickHandler}>counter</button>
      <MemoChildComponent propVal={name} />
    </>
  );
};

export default ParentComponent;

 

 

//  Child component
import React from 'react';

const ChildComponent = ({ propVal }) => {
  console.log('child component rendered', propVal);
  return <></>;
};

const MemoChildComponent = React.memo(ChildComponent);
export default MemoChildComponent;

 

Output:

child component rerenderd poornima.

The child component is not re-rendered, it is rendered only the first time, we have achieved memoization in React.

React.memo() drawback :

  • If we pass a function or an array or object as a prop in the ChildComponent above then it will be re-rendered again. For example let us change the line :

 <MemoChildComponent propVal={name} /> to <MemoChildComponent propVal={someFunc} />

Then the child component will get re-rendered just like how it happened when we didn't use React.memo() Similarly, if we pass some array say const users=['John Doe', 'Jane Doe']

Using useCallback() for memoization:

useCallback() is a hook and it takes two arguments - a callback function and a dependency array, the function is recreated only when the dependency array changes Now let us try to use this in the previous example:

Using useCallback():

The ChildComponent remains the same let's make some changes to the ParentComponent where we create memoized function and pass it as prop:

// ParentComponent.jsx
import { useCallback, useState } from 'react';
import MemoChildComponent from './ChildComponent';

const ParentComponent = () => {
  const [counter, setCounter] = useState(0);
  const clickHandler = () => {
    setCounter((prev) => prev + 1);
  };

  const add2 = () => {
    return 1 + 1;
  };
  const propFunc = useCallback(() => add2(), []);
  return (
    <>
      <p>{counter}</p>
      <button onClick={clickHandler}>counter</button>
      <MemoChildComponent propVal={propFunc} />
    </>
  );
};

export default ParentComponent;
 

newusbmemo.PNG

This time the component is not re-rendered , because we have given an empty array as dependency which means the function is created only on the first render and the value of propFunc never changes.

Using useMemo() for memoization:

Just like useCallback() , useMemo() has two arguments a callback function and a dependency array, and the function is recreated when the dependency array value changes, the only difference is that is that useCallback() memoizes a function whereas useMemo() memoizes the value returned by the function. Let us look at the code example to understand it better:
 

Using useMemo():

The ChildComponent remains the same let's make some changes to the ParentComponent where we create memoized array value by using useMemo() and pass it as a prop:

import { useState, useMemo } from 'react';
import MemoChildComponent from './ChildComponent';

const ParentComponent = () => {
  const [counter, setCounter] = useState(0);
  const clickHandler = () => {
    setCounter((prev) => prev + 1);
  };

  const users = useMemo(() => ['John Doe', 'Jane Doe'], []);
  return (
    <>
      <p>{counter}</p>
      <button onClick={clickHandler}>counter</button>
      <MemoChildComponent propVal={users} />
    </>
  );
};

export default ParentComponent;
 

OutPut:

 

 

memouseMemo.PNGuseMemoop.PNG
 


About Author

Aadarsh Pathak

Aadarsh is an experienced Frontend Developer with expertise in ReactJS, HTML, CSS, JavaScript, and jQuery. With over a year of industry experience, he has contributed to various client and internal projects. One of his notable contributions includes the Reception Module Portal Development (KRB), which is a ReactJS project with a Microservices architecture, encompassing modules such as Reception, Billing, and Physician. Aadarsh's creative mindset and analytical skills enable him to think critically and adapt to new technologies. He is dedicated to staying up-to-date with industry trends through continuous learning and reading.

Request For Proposal

[contact-form-7 404 "Not Found"]

Ready to innovate ? Let's get in touch

Chat With Us