React Suspense comes handy when you want to show an indication to user that something is loading in your app. Loader is the simplest example for a Suspense component. Let’s deep dive into the details of Suspense.
React ensures your user interface stays in sync with the application state by using a technique called re-rendering. During re-renders, React compares the Virtual DOMs and updates the necessary parts of the UI. This process is known as React Reconciliation.
Although React optimizes re-rendering for speed, some tasks can slow it down, leading to performance issues. To address this, React introduced the useMemo
hook.
What is useMemo?
useMemo
is a React Hook that caches the result of a calculation between re-renders.
Syntax:
const cachedValue = useMemo(calculateValue, dependencies);
useMemo
memorizes values between re-renders, recalculating only when dependencies change. This avoids expensive calculations on every render. To the useMemo
you can pass a function and an array of dependencies and it will only recompute the memoized value when one of the dependencies has changed. This avoids expensive calculations on every render and can improve performances.
Parameters
calculateValue
: A pure function that takes no arguments and returns a value to be cached. React calls this function during the initial render and will return the same result on re-renders unless the dependencies change. If dependencies change, React will callcalculateValue
again and return its result.dependencies
: An array of reactive values referenced incalculateValue
. These include props, state, and variables or functions declared directly in the component body. React recalculates the value if any dependency changes.
Remember, don’t do anything there that you wouldn’t normally do while rendering. For example, side effects belong in useEffect, not useMemo.
Usage
Below are the use cases of useMemo
:
- Skipping expensive calculations.
- Skipping re-rendering of components.
- Memozing a dependency of another Hook and function.
Example:
To understand the concept better, let’s dive into the example of skipping the expensive calculation using useMemo
. In the given code, a slow function named slowFunctionNumber
is executed every time the component initializes or the input changes.
However, it also runs whenever the theme button is clicked, despite the theme button having no dependency on the number function. This unnecessary execution can reduce the application’s performance.
Example without useMemo
import {useState} from 'react';
// Simulating a slow calculation
const slowFunctionNumber = (num) =>{
for(var i=1; i<10000; i++){
console.log("slowFunctionNumber called.");
}
return num * 2
}
const NonMemoPage = () => {
const [number, setNumber] = useState(0);
const [dark, setDarkTheme] = useState(false);
const onNumberChangeHandler = (e) => {
setNumber(e.target.value);
};
const onThemeChangeHandler = () => {
setDarkTheme(prevDark => !prevDark);
}
// this function will makes the code slower.
const doubleNumber = slowFunctionNumber(number);
const styleClass = {
backgroundColor: dark ? 'white' : 'black',
color: dark ? 'black' : 'white',
minHeight: '100px'
}
return (
<>
<input type="number" onChange={onNumberChangeHandler} value={number}></input>
<br/>
<button onClick={onThemeChangeHandler}>Change theme</button>
<div style={styleClass}>{doubleNumber}</div>
</>
)
}
export default NonMemoPage;
}
In the above example, slowFunctionNumber
artificially slows down the process by running a loop. In real scenarios, complex calculations might be involved, leading to significant performance issues.
Optimizing performance with useMemo
To prevent slowFunctionNumber
from running unnecessarily, you can use the useMemo
hook, as demonstrated below. With useMemo
, you can see that slowFunctionNumber
is not executed when the theme change button is clicked. This happens because React memoizes the result and avoids re-rendering when there are no changes in the dependencies.
import {useMemo, useState} from 'react';
// Simulating a slow calculation
const slowFunctionNumber = (num) =>{
for(var i=1; i<1000; i++){
console.log("slowFunctionNumber called.");
}
return num * 2
};
const MemoPage = () => {
const [number, setNumber] = useState(0);
const [dark, setDarkTheme] = useState(false);
const onNumberChangeHandler = (e) => {
setNumber(e.target.value);
};
const onThemeChangeHandler = () => {
setDarkTheme(prevDark => !prevDark);
}
// useMemo will remember the function value if the dependencies is not changed.
const doubleNumber = useMemo( () => {
return slowFunctionNumber(number)
}, [number]);
const styleClass = {
backgroundColor: dark ? 'white' : 'black',
color: dark ? 'black' : 'white',
minHeight: '100px'
}
return (
<>
<input type="number" onChange={onNumberChangeHandler} value={number}></input>
<br/>
<button onClick={onThemeChangeHandler}>Change theme</button>
<div style={styleClass}>{doubleNumber}</div>
</>
)
}
export default MemoPage;
How it works
In this above code:
useMemo
is used to memoize the result ofslowFunctionNumber
, ensuring it only re-runs when number changes.- The theme change button now only affects the theme without causing the slow function to re-run, improving overall performance.
Summary
useMemo
is a React hook thats helps optimize performance by memozing the result of functions and ensuring its only re-renders when one of the dependencies are changed.
Example repository
Check out the full working examples in the GitHub Repository.
What are your thoughts on this post?
I’d love to hear from you! Click this link to email me—I reply to every message!
Also use the share button below if you liked this post. It makes me smile, when I see it.