When should you use useMemo in React?

React hooks are a relatively recent addition to the React API. In this post, we will tackle a commonly misunderstood hook, useMemo, and see how it compares to usage in class components.

useMemo

React.useMemo allows developers to memoizeMemoization is a way to store previous results of function calls to optimize performance. expensive function calls in the render function. Here’s an example:

import React from 'react';
require('./style.css');

import ReactDOM from 'react-dom';
import App from './app.js';

ReactDOM.render(
  <App />, 
  document.getElementById('root')
);
You can play around with the minus/plus buttons to see the value change. Checking the box will not trigger a recalculation of the factorial because it's set to only calculate when `counter` changes. The console will show component re-renders, as well as re-calculation of the factorial function.

The factorial method can potentially be very expensive to execute for large numbers, so, in the code above, I used useMemo to memoize it. It will now only run whenever the counter state changes.

Here’s how it works:

useMemo(expensiveFunction, dependencyArray)

The first argument is the function to be memoized – here it’s called the expensiveFunction. This is typically inlined, but it may be extracted as a function outside of your component if you want. The important thing to note is that executing expensiveFunction should return the desired value. To put that in code:

useMemo(expensiveFunction, dependencyArray) === expensiveFunction()

The next argument to look at is the dependencyArray argument. This is an array that tells React which variable changes to look out for. Whenever any variable in this dependency array changes from the last render, whether it is from props or local state, the expensiveFunction will recompute. In ideal situations, expensiveFunction will only recompute when any variable in this dependency array changes.

You will notice that the function still recomputes values it had previously computed – for example, if you changed counter from 2 to 3, then changed it back to 2, it would still re-calculate for 2. This is important to note because React only memoizes one argument at a time. If you had a very expensive function, you may want to create your own memoization function that caches all computation values instead of the last one.

Comparison to class component

How does useMemo compare to usage in a class component? Here is how I would implement it:

import React from 'react';
require('./style.css');

import ReactDOM from 'react-dom';
import App from './app.js';

ReactDOM.render(
  <App />, 
  document.getElementById('root')
);
Optimization of rendering within a class component.

In the code snippet above, you can see that there’s a lot of repetition/boilerplate:

  1. In the componentDidMount
  2. In componentDidUpdate
  3. You need to manually compare prevProps/prevState with this.props/this.state

This can get unwieldy if you have a lot of functions you need to optimize.

Conclusion

Hopefully, this helps you understand how to use React.useMemo and what patterns to look for when shifting your paradigm from class components to hooks.