useMemo is a React Hook that means that you can memoize the results of a calculation.
Memoization caches the results of a calculation to keep away from recalculating it each time it’s wanted.
Memoization can enhance efficiency by decreasing the variety of occasions costly calculations should be carried out.
React.dev reveals an instance of useMemo.
import { useMemo } from 'react';
const cachedValue = useMemo(calculateValue, dependencies)
the place
-
calculateValue
is the perform calculating the worth to cache. The perform needs to be a pure perform and may take no arguments. It could actually return any sort. -
dependencies
is an array of all of the values used insidecalculateValue
.
First, React calls useMemo through the preliminary render, on element mount. The worth returned from the calculatedValue
perform is saved in a variable (cachedValue within the instance above).
Then, for all the subsequent renders, React has a selection:
- If the dependencies haven’t modified, use the identical worth.
- If any dependency modifications, name calculateValue and cache the newly returned worth so it may be reused later.
If the element re-renders for different causes, useMemo ignores the calculateValue
perform and makes use of the cached worth.
Examples
1. Separate Parts & Push State Down
Generally, you may keep away from memoization altogether by pushing the state down, as recommended by Josh Comeau.
The reasoning goes like this.
In case you have two unrelated elements, they will handle their very own state independently when there is no such thing as a purpose to raise the state up.
In so doing, the 2 elements are impartial. In different phrases, the rendering and re-rendering of ComponentOne does not have an effect on ComponentTwo, and vice-versa.
If the heavy computation occurs in a single element, the re-rendering of the opposite element does not set off heavy computations once more.
On this example on StackBlitz, I’m utilizing the Clock element from Josh Comeau’s article, and I’m fetching knowledge from jsonplaceholder in a second element referred to as Customers.
Since Clock and Customers are impartial of one another, React re-renders the Clock element each second however not the Customers element, which comprises an costly HTTP request.
// App.tsx
...
export const App: FC<{ identify: string }> = ({ identify }) => {
return (
<div>
<h1>Hey {identify}!</h1>
<Clock />
<Customers />
</div>
);
};
This resolution can also be really helpful on react.dev: “Desire native state and don’t raise state up any additional than essential.”
Nonetheless, in some circumstances, it’s not attainable to push the state down. However possibly you may raise the content material up, as recommended by Dan Abramov in Before you memo().
2. Raise Content material Up & Use Youngsters Prop
Right here is the instance of Dan Abramov, the place the ExpensiveTree elements should not be re-rendered if attainable.
export default perform App() {
let [color, setColor] = useState('purple');
return (
<div type={{ coloration }}>
<enter worth={coloration} onChange={(e) => setColor(e.goal.worth)} />
<p>Hey, world!</p>
<ExpensiveTree />
</div>
);
}
A attainable resolution is to “cut up the App element in two. The components that rely upon the colour, along with the colour state variable itself, have moved into [a new component called] ColorPicker“
// ColorPicker
perform ColorPicker({ youngsters }) {
let [color, setColor] = useState("purple");
return (
<div type={{ coloration }}>
<enter worth={coloration} onChange={(e) => setColor(e.goal.worth)} />
{youngsters}
</div>
);
}
“The components that don’t care in regards to the coloration stayed within the App element and are handed to ColorPicker as JSX content material, also referred to as the kids prop.“
So the restructured App element turns into
// App
...
export default perform App() {
return (
<ColorPicker>
<p>Hey, world!</p>
<ExpensiveTree />
</ColorPicker>
);
}
“When the colour modifications, ColorPicker re-renders. However it nonetheless has the identical youngsters prop it received from the App final time, so React doesn’t go to that subtree.
And because of this, doesn’t re-render.”
This resolution can also be really helpful by react.dev: “When a element visually wraps different elements, let it settle for JSX as youngsters. This fashion, when the wrapper element updates its personal state, React is aware of that its youngsters don’t have to re-render.“
If these options do not work, we’ve to resort to memoization.
3. Memoize Parts
Let’s return to the primary instance the place we pushed the state down.
If the Clock element logic can’t be pushed down, it stays within the App element. React re-renders the App element (and all youngsters) each time a change happens (each second). You will discover this instance on this StackBlitz.
// App.tsx
...
// Use useMemo round Customers
export const App: FC<{ identify: string }> = ({ identify }) => {
const time = useTime();
return (
<div>
<h1>Hey {identify}!</h1>
<p>{format(time, 'hh:mm:ss a')}</p>
<Customers />
</div>
);
};
To maintain Customers from re-rendering and triggering a fetch request each second we are able to wrap Customers round useMemo earlier than exporting it.
// Customers.tsx
...
const Customers: FC = () => { ... }
export default React.memo(Customers);
That is barely totally different from the useMemo
syntax we noticed above.
const cachedValue = useMemo(calculateValue, dependencies)
That’s as a result of we’re utilizing memo
and never useMemo
.
The primary distinction between memo and useMemo is that memo is a higher-order element (HOC) and useMemo is a React Hook.
-
memo is used to memoize a React element, which signifies that it caches the output of the element and solely re-renders it if its props have modified. This may be helpful when a element’s rendering is dear, and also you wish to keep away from pointless re-renders.
-
useMemo is used to memoize the results of a perform inside a element. This may be helpful when it is advisable carry out an costly calculation, and also you wish to keep away from recalculating it each time the element re-renders.
4. Memoize Parts And Change Props
There is no such thing as a array of dependencies in memo
. So what if we have to set off the costly operation once more?
If we’re memoizing a element, the element will solely be re-rendered if its props change.
So here’s a memoized component with changing props.
First, we added three buttons so you may select what knowledge you wish to fetch:
When you click on a button, the chosen merchandise can be saved within the merchandise
variable and handed to the Customers element
// App.tsx
...
export const App: FC<{ identify: string }> = ({ identify }) => {
const [item, setItem] = useState<Objects>('albums');
const time = useTime();
return (
<div>
<h1>Hey {identify}!</h1>
<p>{format(time, 'hh:mm:ss a')}</p>
<button onClick={() => setItem('customers')}>Customers</button>
<button onClick={() => setItem('posts')}>Posts</button>
<button onClick={() => setItem('albums')}>Albums</button>
<Customers merchandise={merchandise} />
</div>
);
};
Second, we modified the code in Customers to make use of the prop handed in from App.tsx.
The brand new prop known as merchandise
and is of sort Objects (you may see every type I used on StackBlitz).
The string assigned to merchandise
is then used to fetch the proper knowledge from jsonplaceholder. Fetched knowledge is saved in gadgets
and used within the template to render an inventory of things within the Customers element (at this level we must always rename the element as a result of it might render different issues).
// Customers.tsx
const Customers: FC = ({ merchandise }: { merchandise: Objects }) => {
const [items, setItems] = useState<Person[] | Album[] | Publish[]>(null);
useEffect(() => {
fetch(`https://jsonplaceholder.typicode.com/${merchandise}`)
.then((response) => response.json())
.then((knowledge) => setItems(knowledge));
}, [item]);
console.log(gadgets);
return (
<div>
{gadgets &&
gadgets.map((merchandise: Person | Album | Publish) => (
<p key={merchandise.id}>
{merchandise.identify} {merchandise.title}
</p>
))}
</div>
);
};
export default React.memo(Customers);
Notice that whenever you take a look at the console, you will note two logs each time you choose an merchandise. It’s because fetching knowledge is an asynchronous operation.
The primary log will print the info that’s already in gadgets
(the outdated knowledge) and the second log will print the newly fetched knowledge.
This works effective so long as merchandise
shouldn’t be a set (e.g. not an array or object).
The issue with arrays is that “each time React re-renders, we’re producing a model new array. They’re equal when it comes to worth, however not when it comes to reference.”
In different phrases, they’re utilizing two totally different areas in your laptop’s reminiscence.
So, if merchandise
is an array (let’s name it itemArray), we are able to memoize it as follows:
const itemArray = React.useMemo(() => {
return [
{ id: 1, value: 'users' },
{ id: 2, value: 'posts' },
{ id: 3, value: 'albums' },
];
}, []);
This closes the circle by going again to the preliminary useMemo
syntax we began with.
Nonetheless, I encourage you to learn a extra complete rationalization about Preserved References
Abstract
Memoization caches the results of a calculation to keep away from recalculating it each time it’s wanted.
Use the HOC memo to memoize elements and useMemo to memoize the results of a perform.
Earlier than utilizing memoization, attempt to push the state down or raise the content material up.
In various use memoization.
As a rule of thumb,
- Solely memoize values which are costly to calculate.
- Do not memoize values which are continuously up to date.