React Memoization

Jeff P
3 min readJan 29, 2024

what it is and how to use it

React memoization is a performance optimization technique used in React to avoid unnecessary rendering of components and improve application performance. Memoization involves caching the results of expensive computations or expensive function calls and reusing those cached results when the same computation is requested again, rather than recalculating them.

Memoization is commonly associated with the memo() higher-order component and the useMemo hook.

When you wrap a component with memo, it memoizes the component by caching its rendered output based on the props passed to it.

const MemoizedComponent = memo(MyComponent);

If the component receives the same props in subsequent renders, it will reuse the cached output, preventing the component from re-rendering.

You can also simply memo the component at the point of export… for example:

import { memo } from "react";

function ToggleSounds({ allowSound, setAllowSound }) {
return (
<button
className="btn-sound"
onClick={() => setAllowSound((allow) => !allow)}
>
{allowSound ? "🔈" : "🔇"}
</button>
);
}

export default memo(ToggleSounds);

So this is a simple toggle function which sets a piece of state to true or false when the use clicks a button.

You can confirm it has been memoized in the React tools profiler…

Now whilst that sounds good, but you have to remember that when arrays, objects or functions are re-rendered, they are technically new versions, even if the code is identical!

{} != {}

Now if objects or functions are passed as props, then the child component will always see them as new props, in which case the memo() higher-order component will NOT work.

This is where the useMemo() hook comes in.

useMemo

  • useMemo is a hook in React that allows you to memoize the result of a computation or function call.
  • It takes two arguments: the function or computation to be memoized, and an array of dependencies.
  • The function is only re-executed when one or more of the dependencies change.
const memoizedValue = useMemo(() => computeExpensiveValue(
dep1, dep2
), [dep1, dep2]);

The memoized value remains the same if both dependencies remain unchanged.

Here’s a real-world example of utilizing useMemo()

Firstly…a piece of code that has NOT been memoized..

  const workouts = [
{
name: "Full-body workout",
numExercises: partOfDay === "AM" ? 9 : 8,
},
{
name: "Arms + Legs",
numExercises: 6,
},
{
name: "Arms only",
numExercises: 3,
},
{
name: "Legs only",
numExercises: 4,
},
{
name: "Core only",
numExercises: partOfDay === "AM" ? 5 : 4,
},
];

This is an array of workout types. This is passed to the Calculator component…

  return (
<main>
<h1>Workout timer</h1>
<time>For your workout on {time}</time>
<ToggleSounds allowSound={allowSound} setAllowSound={setAllowSound} />
<Calculator workouts={workouts} allowSound={allowSound} />
</main>
);

So each time the App component re-renders, the Calculator component will also re-render.

But why would App.js be re-rendering every second? This is currently down to the following piece of code:

useEffect(function () {
const id = setInterval(function () {
setTime(formatTime(new Date()));
}, 1000);

return () => clearInterval(id);
}, []);

so the “time” piece of state is being updated every 100ms (1 second) with the setTime function, and because this causes App to re-render, it means that Calculator will re-render as App contains the array mentioned above, which is passed as props into Calculator.

We can fix this by applying useMemo() to our array, to ensure it doesn’t change unless the values inside it change.

It’s essential to use memoization carefully and not overuse it, as excessive memoization can lead to increased memory consumption. It’s most effective when applied to specific components or computations where the performance gain justifies the complexity it adds to the code.

useCallback()

The useCallback hook in React is used for memoizing functions in a way that prevents them from being recreated on each render, similar to how useMemo memoizes values.

  // Define a function using useCallback
const handleClick = useCallback(() => {
setCount(count + 1);
}, [count]);

--

--

Jeff P

I tend to write about anything I find interesting. There’s not much more to it than that really :-)