It’s confusing when we should use useMemo
and when we shouldn’t.
useMemo isn’t free $
useMemo
comes with a small cost. So we should understand when it’s a benefit, and when it doesn’t provide any value.
- Small usage in RAM to memoize & remember the resulting value
- It costs a small cpu cycle to loop over & compare the dependency array & run internal fn of useMemo
So we should be smart when we use it.
useMemo isn’t always needed
useMemo
isn’t needed in certain cases. For example, casting something to Boolean, or doing simple math isn’t an expensive operation and returns a primitive like “boolean” or “number”. These value will always be the same every time they are re-render run
true === true
and 5 === 5
.
Conversely, an array or object don’t have equality,
[] !== []
and {} !== {}
and new Date !== new Date
.
Two tests of if you need useMemo
- Is the calculation to get the value is complex (looping, calculating, initializing a class)?
- Or is it cheap (comparisons of numbers, boolean, casting types, simple math)
- Is the returning complex value (object, array, fn, or class)?
- Or is it a primitive value that is simple to compare (number, boolean, string, null, undefined)
Examples
const date = useMemo(() => Date.parse(isoDateString), [isoDateString]);
We should use useMemo
- 🛑 Initializes the Date class
- 🛑 Returns a Date Object, which is not a primitive
const isAdmin = useMemo(() => runExpensiveSearch(accounts), [accounts]
We should use useMemo
- 🛑 Runs an expensive function to get the value
- ✅ Returns a primitive value
In cases where it’s neither an expensive calculation nor a complex object, useMemo
isn’t necessary.
- const isArchived = useMemo(() => Boolean(process?.deletedAt), [process?.deletedAt]); + const isArchived = Boolean(process?.deletedAt);
We don’t need useMemo
- ✅ Casts to a boolean which is a cheap operation
- ✅ Returns a primitive value
- const numberOfAccounts = useMemo(() => accounts.length, [accounts]); + const numberOfAccounts = accounts.length;
We don’t need useMemo
- ✅ Getting the length property is cheap
- ✅ Returns a primitive value
Just remember the two tests
- Is it complex / expensive function?
- Is the value not a primitive?
What about useCallback?!
I’m so glad you asked! The principles are similar. In general, all callback functions should be memoized via useCallback. Functions are considered a non-primitive value thus never have equality unless we memoize them via useCallback.
(Cover Photo: Feldstraße Bunker, Hamburg, Germany – Jonathan Stassen / JStassen Photography)