Welcome back to the series of React Hooks.
Series path
The main objective will be to explore how re-rendering works in React, why that is a critical factor for React applications, and how the useMemo
hook can leverage it to build a performance boost in your applications. We will also see when useMemo
can cause performance issues.
What is useMemo
hook?
useMemo()
is a built-in React hook that accepts two arguments — a function compute that computes a result and the dependencies array:
const memoizedResult = useMemo(compute, dependencies);
Let us try to get the essence of the useMemo
hook. During the first rendering, useMemo(compute, dependencies)
invokes the compute
function, which is the first argument, memoizes the calculation result, and returns it to the component.
If during the next renderings the dependencies change, then useMemo()
invokes compute
, memoizes the new value, and returns it. But if dependencies don't change during re-rendering, then useMemo()
doesn't invoke compute
but returns the memoized value.
When to Use useMemo
?
The basic and first step is to write the code first and then revisit it to see if any optimization can be made.
Implementing
useMemo
too often in an application can harm the performance.
When looking to implement useMemo
, you can check with profiling tools in the debugger to identify any expensive performance issues. By expensive, I mean if the application is consuming a lot of resources (memory). It makes sense to memoize with useMemo
only if you declare a large number of variables in a function at render.
Example
A component <ComputeFactorial />
calculates the factorial of a number introduced into an input field.
Here’s a possible implementation of <ComputeFactorial />
component:
import { useState } from "react";
export const ComputeFactorial = () => {
const [number, setNumber] = useState(1);
const [inc, setInc] = useState(0);
const factorial = getFactorialOf(number);
return (
<div>
Factorial of
<input
type="number"
value={number}
onChange={(event) => setNumber(Number(event.target.value))}
/>
is {factorial}
<button onClick={() => setInc((i) => i + 1)}>Force Re-render</button>
</div>
);
};
function getFactorialOf(n) {
console.log("getFactorialOf(n) is called!");
return n <= 0 ? 1 : n * getFactorialOf(n - 1);
}
Every time the input value is changed, the factorial is calculated usinggetFactorialOf(n)
and 'getFactorialOf(n)
is called!' is logged to console.
On the other hand, each time you click the Force Re-render
button, the inc
state value is updated. Updating the inc
state value triggers <ComputeFactorial />
component to re-render. When a component is re-rendered, the factorial is recalculated again — 'getFactorialOf(n)
is called!' is logged to console.
How can you memoize the factorial calculation when the component re-renders? Welcome useMemo()
hook!
By using useMemo(() => getFactorialOf(number), [number])
instead of simple getFactorialOf(number)
, React memoizes the factorial calculation.
Let’s improve <ComputeFactorial />
and memoize the factorial calculation:
import { useState, useMemo } from "react";
export const ComputeFactorial = () => {
const [number, setNumber] = useState(1);
const [inc, setInc] = useState(0);
const factorial = useMemo(() => getFactorialOf(number), [number]);
return (
<div>
Factorial of
<input
type="number"
value={number}
onChange={(event) => setNumber(Number(event.target.value))}
/>
is {factorial}
<button onClick={() => setInc((i) => i + 1)}>Force Re-render</button>
</div>
);
};
function getFactorialOf(n) {
console.log("getFactorialOf(n) is called!");
return n <= 0 ? 1 : n * getFactorialOf(n - 1);
}
Every time the value of the number is changed, 'getFactorialOf(n)
called!' is logged to console, which is expected.
However, if you click Force Re-render button, 'getFactorialOf(n) is called!
' isn’t logged to console because useMemo(() => getFactorialOf(number), [number])
returns the memoized factorial calculation. How cool is that!
Wrapping up
This article explored the useMemo
hook and when it is appropriate to use it in a React application.
We also see that useMemo
helps in boosting the performance of an application by "remembering" or memoizing expensive functions and preventing a re-render every time there is a change in the application.
We also learnt that while using useMemo
can improve the application's performance, overusing useMemo
can slow down your application. This means the more useMemo
hook is used, and the memory has to be allocated for the memory.
If you have any questions, suggestions, corrections, I will look forward to it. Thank you for making it this far.
Series path
💌 If you'd like to receive more tutorials in your inbox, you can sign up for the newsletter here.
Top comments (0)