React.memo() vs. useMemo()

What are the major differences between React.memo() vs useMemo()?

Piumi Liyana Gunawardhana
Bits and Pieces

--

Performance optimization is an important factor in web development. React uses “memoization” as an optimization technique to speed up the rendering process of the components. It offers React.memo() and useMemo() to implement memoization.

This article will compare and contrast React.memo and useMemo() while discussing their use cases.

The need for React.memo() and useMemo()

The best way to understand why we need React.memo() and useMemo() is to see how React re-renders components without memoization.

For this, let’s consider a simple example with 2 React components. The first component is the parent component. It has a button that increases the value of the count variable.

import Child from "./Child";
import "./styles.css";
import React from "react";
import { useState} from "react";

//Parent.js
export default function Parent() {
const [count, setCount] = useState(0);
const handleClick = () => { setCount(count + 1); };
console.log("Parent Render");

return (
<div>
<button onClick={handleClick}>Increase Count</button>
<h2>{count}</h2>
<Child name={"Child Component"} />
</div>
);
}

The second component is the child component, and it displays the name passed from the parent component.

import React from "react"; 

//Child.js
export default function Child(props) {
console.log("Child Render");
return (
<div>
<h2>{props.name}</h2>
</div>
);
}

Once the user clicks Increase Count button, the count will increase, and it will cause a re-render in the parent component. Here, the value change of the count variable doesn't affect the props passed into the child variable, and the child component should not re-render.

Screenshot by author

However, as you can see, the child component’s render method is also invoked whenever the parent component is re-rendered. This will trigger the child components’ virtual DOM to do a variance check against the previous virtual DOM state. But, the real DOM will not change because the child component has no changes.

Although the real DOM does not change, it will take some time to compare with virtual DOM to see identical. Therefore, this behaviour can cause significant performance issues and increase the loading times in large-scale applications.

That’s why we need to use React.memo() and useMemo() to optimize the React component rendering process.

What is React.memo()?

React.memo() was introduced with React 16.6 to avoid unnecessary re-renders in functional components. It is a higher-order component that accepts another component as a prop. It will only render the component if there is any change in the props.

Let’s now examine the above example again to understand how React.memo() works. But, this time, we need to wrap the child component with React.memo().

import React from "react"; 

//Child.jsexport
function Child(props) {
console.log("Child Render");
return (
<div>
<h2>{props.name}</h2>
</div>
);
}

export default React.memo(Child); //Add React.memo() HOC to the child component

When we click the Increase Count button, the child component won't be re-rendered, and the application will reuse the previous rendered output.

Screenshot by author

It is important to keep in mind that React.memo() will only check for the prop alterations. If the functional component has a useState, useReducer, or useContext Hook, it will still force a re-render when the state or context changes.

In addition, React.memo() will shallowly compare complex objects in the props object. If you want more authority over the comparison, you can also pass a custom comparison function as the second argument as shown below:

export function Child(props) { 
/* render using props */
}
function areSame(prevProps, nextProps) {
/* return true if passing nextProps to render would return the same result as passing prevProps to render, otherwise return false */
}

export default React.memo(Child, areSame);

When should we use React.memo()?

It is best to use React.memo() when:

  • Components are rendered too frequently and slow down the application.
  • Component renders’ cost is high (When the loading time is more than 100ms).
  • Component keeps re-rendering for the same set of props.

However, using React.memo() in lightweight components can cause performance overheads and unexpected errors. Thus, we should also think about the complexity of the component when using React.memo().

What is useMemo()?

useMemo() is one of the most used React Hooks among developers. It takes a function and a dependency array as input and memoizes the value returned by that function.

The specialty of useMemo() is that it will only recalculate the memoized value when one of the dependencies changes. This optimization helps avoid costly calculations on each render.

Let’s now turn to an example to understand how useMemo() works.

import Child from "./Child";
import React from "react";
import { useState, useRef, useMemo} from "react";

//Parent.js
export default function Parent() {
const [counts, setCounts] = useState(0);
const [times, setTimes] = useState(0);
const handleClick = () => {
setCounts(counts + 1);
};

const useMemoRef = useRef(0);
const incrementUseMemoRef = () => useMemoRef.current++;
const memoizedValue = useMemo(() => incrementUseMemoRef(), [times]);

console.log("Parent Render");

return (

<div>
<button onClick={() => setTimes(times + 1)}>Force Child Render</button>
<br></br>
<br></br>
<button onClick={handleClick}>Increase Count</button>
<Child memoizedValue={memoizedValue} />
</div>
)
}

This shows that in the parent component, we are using useRef()Hook to keep track of the number of times the child component re-renders. The useMemo() Hook invokes the incrementUseMemoRef function, and the value returned by the useMemo() Hook is then stored in the memoizedValue variable. It increases the value of our useMemoRef.current by one each time the dependencies update. You will see that if you click the Increase Count button, the memoizedValue doesn't get updated.

import React from "react";

//Child.js
function Child({memoizedValue}) {
console.log("Child Render");

return (
<div>
<h2>Child Component</h2>
<p>
I'll only re-render when you click <b>Force Child Render.</b>
</p>
</div>
)
}

export default React.memo(Child);

The child component will only be re-rendered when you click the Force Child Render button since the memoizedValue gets updated.

Screenshot by author

When to use useMemo?

Before using the useMemo() hook, you need to make sure that:

  • You’ve analyzed the component and verified whether it calculates a costly value in every render.
  • Since it executes while rendering, your useMemo() hook has no side effects, and all side effects reside in the useEffect() hook.
  • You don’t break any React Hooks rules and standards.

The ideal situation to use useMemo()is when you have computationally intensive functions. useMemo() function can memoize the value returned by your function and keep it in memory across renders. In most situations, it returns a result that you can't run outside of your React component.

This is similar to saving a function response into a variable and then referencing the response value from the variable without executing the function each time.

Should you use React.memo() or useMemo()?

Choosing between React.memo() and useMemo() should be straightforward. Now you have a good understanding of both of them.

  • Use React.memo to memoize an entire component.
  • Use useMemo to memoize a value within a functional component.

Build composable web applications

Don’t build web monoliths. Use Bit to create and compose decoupled software components — in your favorite frameworks like React or Node. Build scalable and modular applications with a powerful and enjoyable dev experience.

Bring your team to Bit Cloud to host and collaborate on components together, and greatly speed up, scale, and standardize development as a team. Start with composable frontends like a Design System or Micro Frontends, or explore the composable backend. Give it a try →

Learn More

--

--

Software Engineer | Technical Writer | BSc. IT(Hons) University of Moratuwa — Faculty of IT