When you first get introduced to concepts like useMemo, React.memo and useCallback, it can be difficult to understand the differences and when to use each one and when not to.
This article will explain what the difference is between React.memo and useMemo and when to use them.
If you haven’t done so already, I highly recommend having a quick read through my article that covers the differences between useMemo and useCallback so you will get a better understanding of this article.
With that being said, my goal with this post is to explain these concepts for everyone. You don’t need any prior experience with useMemo, useCallback or React.memo.
So, let’s get stuck in.
What is the difference between React.memo vs useMemo?
React.memo is a higher-order component (or HOC for short) which accepts a react component and an optional function that uses props to conditionally update the component using memoization, whereas useMemo is a react hook that will accept a function and a dependency array and then memoize the value returned from the function passed into it.
You can think of Memoization as a function that remembers something. In useMemo it remembers the value returned between renders, and in React.memo it remembers the react component between renders.
We will cover both React.memo and useMemo in more detail a little later on in this article, but firstly I wanted to give you a brief overview of what both look like in these next examples:
React.memo example:
export function MyReactComponent({ myNumber }) {
return <p>{myNumber * 5}</p>
}
export default React.memo(MyReactComponent, function areEqual(
prevProps,
nextProps
) {
if (prevProps.myNumber !== nextProps.myNumber) {
return false
}
return true
})
As you can see here React.memo is a higher-order component that accepts a react component and memoizes it depending on your props.
useMemo example:
export function MyReactComponent({ myNumber }) {
const result = useMemo(() => myNumber * 5, [myNumber])
return <p>{result}</p>
}
As you can see here useMemo is a react hook that gets run within a react component and memoizes a value.
How do dependencies get managed with React.memo vs useMemo?
Dependencies here mean the values/variables that will cause your memoized function or component to re-render or re-run when new values are passed in.
Dependencies with React.memo
In React.memo you need to provide your react component as well as an optional function to handle when it should be updated.
If you don’t provide the optional function React.memo will automatically shallowly compare your props and re-render whenever they change.
The function you provide will handle the dependencies by accepting two parameters which are the previous and the next props.
It is then your job to use the previous and next props to decide if your component needs to be re-rendered by returning a boolean of either true or false.
React.memo’s dependency function expects to have the question of "Are the props still the same?"
answered.
With that in mind, if you return true
you are saying that, "Yes, the props are the same, please don't re-render this component"
.
If you return false
, you are saying "No, these props are not the same, please re-render my component"
.
React.memo second argument example:
export default React.memo(MyReactComponent, function areEqual(
prevProps,
nextProps
) {
if (prevProps.myNumber !== nextProps.myNumber) {
return false
}
return true
})
As you can see if the prop myNumber
changes we will return false
to indicate that the props are no longer the same and to then re-render our component, however if it does not then we will return true
to show that the props are the same and to not re-render the component.
Dependencies with useMemo
useMemo handles dependencies slightly differently than React.memo. useMemo, instead of a function with props, it accepts a dependency array for the second argument.
The dependency array in useMemo, will check for changes in the array between renders, if any of the values have changed then it will re-run your function to get a new memoized value.
useMemo dependency array example:
export function ExampleComponent({ myNumber }) {
const answer = useMemo(() => myNumber + 5, [myNumber])
return <p>{answer}</p>
}
As you can see in this example we have used useMemo with our function () => myNumber + 5
and the dependency array for the function [myNumber]
.
In this example, useMemo will only re-run the function when the prop myNumber
changes.
When should you use React.memo?
When developing a react application, it is actually pretty rare to have the need to use React.memo, and generally speaking you should avoid it unless you notice a big issue with your performance due to re-renders.
Most of the time, you can probably fix performance issues by just passing only the relevant props into the relevant component.
You may also be able to restructure your application to once again avoid the need to use React.memo.
In some cases, your component may render many times, but if it is a light component then there isn’t really anything too bad about that and the trade off for using React.memo may end up being worse than just letting it re-render.
With that said, if you have tried similar solutions with no success and you are noticing that your application is lagging behind because of a component being rendered too often, then here you may want to use React.memo to prevent it from being rendered unless certain props change.
The other benefit to using React.memo is that you can completely control when your component is rendered.
By using React.memo you can deep compare props yourself so you can accurately choose when the component is rendered.
It is also worth noting that this will affect the child components of your memoized component, which can either help improve the performance even more or lead to unexpected bugs, so be careful here and make sure that any child components will still be able to accurately work with the parent memoized component.
When should you use useMemo?
Similar to React.memo, you should try to avoid using useMemo wherever possible and find alternative optimizations, such as moving your function definition and execution outside of your react component.
You can see a full list of optimization ideas here to try first
Now that is out of the way, let’s get onto when you might need to use it.
If you have a computationally expensive function that returns a result that you cannot run outside of your react component, this might be the ideal time to use useMemo.
useMemo is designed to remember/memoize the value that is returned from your function and persist it in between renders.
By doing this you will avoid having to actually run the computationally expensive function on every render of your react component.
You can think of this similar to saving a function response into a variable and then using the variable to reference the response value rather than running the function each and every time.
useMemo example:
import React, { useEffect, useMemo } from "react"
import { massiveArray } from "./massiveArray"
export const filterAndMapMassiveArrayToNumber = number => {
// There are much better ways and algorithms to do this sorting,
// this is only for illustrating the purpose of useMemo.
return massiveArray
.map(item => ({
...item,
value: item.value * myNumber,
}))
.filter(item => item.value > 10)
}
export default function UseMemoWithExpensiveFunctionExample({ myNumber = 1 }) {
const finishedArray = useMemo(
() => filterAndMapMassiveArrayToNumber(myNumber),
[myNumber]
)
return (
<ul>
{finishedArray.map(item => (
<li key={item.id}>{item.value}</li>
))}
</ul>
)
}
As you can see, we have a fairly resource heavy function that we need to run here, and thanks to useMemo we are now only ever running the function when the variable myNumber
is changed because we have included it in the dependency array.
Further reading:
I hope you enjoyed reading this article!
Will