React Memoization Cheatsheet: 5 different ways to memoize and why it matters
React is improving fast and new versions pack a lot of different cool features built into the library. One of the coolest is the set of tooling around Memoization. In this post we'll learn a few tips and tricks on the subject, things I've used in production and helped me speed up heavy renders.
Why it matters
Already know why it matters? Go straight to the cheat sheet ⏭
Memoizing is a well-known concept in computer programming, aiming to speed up programs by caching results of expensive function calls and re-using those cached results as to avoid repeating those expensive operations:
Memoization speeding up an expensive component's render
When using React, depending on how big and complex your component tree is, the process of rendering might be one of these expensive operations. The process of reconciliation alone might already be too heavy if it always has to go over the whole tree. This kind of computation, when done in the UI thread, can impose a heavy tax on the user experience, making your UI non-responsive and sluggish. In fact if we want to meet RAIL's goals and guidelines we have 50ms of time to do computations before we actually respond to user input.
A heavy, unresponsive and sluggish UI can lead to frustrated users and a sense of fatigue while using your application and on React application avoiding re-renders is usually one of the most impactful performance improvements you can do on Rendering Performance
The Cheat Sheet
This is the actual cheatsheet :) If you know some other ways to use memoization, lemme know!
Memoizing Components
When a component does not need to render when it's props change, we can let React know that so that it won't try to render from that component down unless it has to.
Note that the advantage of Memoizing shared.components only pays off when rendering is expensive. For simple children trees it can be quicker to just do the render compared to the overhead of comparing props.
Function Components
React comes with an awesome
HoC:
React.memo
that allows us
to memoize function shared.components:
Class Components
React has shipped with shouldComponentUpdate
for a long time.
shouldComponentUpdate
is a method which is used in the
reconciliation algorithm to tell
if a component should trigger it's render()
method or not. Like with
React.memo
there's an easy way to implement that comparison if we only need a
default shallow comparison of props:
React.PureComponent
Note that shouldComponentUpdate is the opposite of the comparison function for React.memo which can be interpreted as a
areEqual
function
Memoizing Props
When using literals, like string
and number
shallow comparison usually
suffices for component memoization. However if we're using functions and
objects, we need to memoize them in a different way. Because:
Don't worry though, React ships with some cool helpers for that too :)
Memoizing Functions
To memoize functions, we can use
useCallback
Example of usage in a component
Memoizing heavy computations, Objects, Arrays, Sets, etc
To memoize the return of heavy computation functions, Objects, Arrays, Sets, etc
we can use
useMemo
. We're
meant to use this only if the value needs to change based on a certain
property, if you need a consistent reference there is another
way
Up until now, we were memoizing values to prevent the render from happening.
With useMemo
however, we can prevent heavy computation from happening as well
by storing a value in memory.
Example of usage in a component
Note that most of the time you shouldn't be doing heavy computation inside render methods, if possible, you should avoid doing that in the UI thread altogether. If you're interested, Surma has a really good article on how to move computation off of the main thread
Consistent Reference When Content Does Not Change
To get a consistent reference to a value, we can use the useRef hook:
Example of usage in a component (useRef)
We can use it to get a reference to initial prop values as well:
See Also
- React Top Level API -- React;
- Hooks API Reference -- React;
- Hooks FAQ -- React;
- You’re overusing useMemo: Rethinking Hooks memoization -- LogRocket Blog;
- Measure Performance with the RAIL Model -- Web Fundamentals;
- Rendering Performance -- Web Fundamentals
- Use web workers to run JavaScript off the browser's main thread -- web.dev