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 graph showing expensive vs cached renders 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

  1. React Top Level API -- React;
  2. Hooks API Reference -- React;
  3. Hooks FAQ -- React;
  4. You’re overusing useMemo: Rethinking Hooks memoization -- LogRocket Blog;
  5. Measure Performance with the RAIL Model -- Web Fundamentals;
  6. Rendering Performance -- Web Fundamentals
  7. Use web workers to run JavaScript off the browser's main thread --