What is useMemo hook
useMemo() hooks is used to prevent expensive calculation on every render by using memoization.
useMemo() returns a memoized value only when its dependencies changes.
What is Memoization
Memoization is an optimization technique. It is used to speed up the computer program/component performance by storing the result of expensive operation and using the stored value if there is no change in the result.
If there is no change in the result of expensive function then it will not be recalculated but the stored value(cached value) will be used.
Optimizing the component using useMemo() hook
let's see an example of how to use useMemo hook and when to use it.
First we need to create a react app. We can do so by using the below command
npx create-react-app myApp
Next I have create a function named ExpensiveCalculation in a js file of same name.
function ExpensiveCalculation(num) {
console.log("calculating...");
for (let i = 0; i < 1000000000; i++) {
num += 1;
}
return num;
}
export default ExpensiveCalculation;
the above function is the expensive function which decreases the performance of the component. The above function will add 1 to the num
which is passed as a parameter in ExpensiveCalculation.
The for loop checks if the value of i
is less than 1000000000, if this is true, 1 will be added to the previous value of num
and then function will return the updated num
value.
Then I have created a component named AddItems.js in src folder. Let's see how is the performance of the component without useMemo.
import { useState} from "react";
function AddItems() {
const [items, setItems] = useState([]);
const [count, setCount] = useState(1);
// without memoization --> expensive calculation
const calculation = ExpensiveCalculation(count)
const addItems = () => {
setItems((prev) => [...prev, `New item`]);
};
const incrementCount = () => {
setCount((c) => c + 1);
};
return (
<div>
{items.map((item) => (
<li>{item}</li>
))}
<button onClick={addItems}>Add items</button>
<div style={{ display: "flex" }}>
<h2>Expensive Calculation</h2>
<button onClick={incrementCount}>calculate</button>
{calculation}
</div>
</div>
);
}
export default AddItems;
ExpensiveCalculation is assigned to const calculation. No memoization is used here.
There is a button Add Item
which add new items and it will be displayed in the browser.
There is another button calculate
which will increment the count
Now whenever we click on button calculate
the count will increment and count is passed as argument in ExpensiveCalculation.
const calculation = ExpensiveCalculation(count)
In the file ExpensiveCalculation for loop will run and will check if i is less than 1000000000. This will take sometime because 1000000000 is a big value so AddItem will take time to re-render the updated value.
Now when we click on Add Item
button, ExpensiveCalcution will run as well and AddItem component will take longer to re-render even though we just wanted to add new item and display it.
Because of ExpensiveCalculation, There is a delay in execution and AddItem component is taking longer to re-render. To fix this performance issue we will use useMemo hook.
To use memoization in react we have to import useMemo hook from react
const calculation = useMemo(()=>ExpensiveCalculation(count),[count])
useMemo hook accepts a second parameter to declare dependencies. in the above code ExpensiveCalculation function will be called only when there is change in count.
We can see that when count value is not changed then function returns the cached value and there is no lag when we click on add item button.
Below is the complete code after using useMemo hook.
import { useState, useMemo } from "react";
import ExpensiveCalculation from "./ExpensiveCalculation";
function AddItems() {
const [items, setItems] = useState([]);
const [count, setCount] = useState(1);
//with useMemo hook
const calculation = useMemo(() => ExpensiveCalculation(count), [count])
const addItems = () => {
setItems((prev) => [...prev, `New item`]);
};
const incrementCount = () => {
setCount((c) => c + 1);
};
return (
<div style={{ display: "flex", displayDirection: "row", gap: "5rem" }}>
<div>
{items.map((item, idx) => (
<li key={idx}>{item}</li>
))}
<button onClick={addItems}>Add items</button>
</div>
<div>
<h2>Expensive Calculation</h2>
<button onClick={incrementCount}>calculate</button>
{calculation}
</div>
</div>
);
}
export default AddItems;
React forget some previously memoized values and recalculate them on next render to free memory. Write your code so that it still works without useMemo — and then add it to optimize performance.
Top comments (0)