Bad ways you’re using react – useMemo

Share This Post

Yo, it’s your boy gabe back with another edition of “Bad ways you’re probably using React.” Today, we’re going to talk about a common mistake that developers make (and I made, up until last year) when using React: not using the useMemo hook.

 

As Kanye West once said, “I hate when I’m on a flight and I wake up with a water bottle next to me like oh great now I gotta be responsible for this water bottle.” Just as he dislikes being responsible for something he didn’t need, React developers don’t want to be responsible for re-rendering components unnecessarily.

 

React components can re-render frequently, even if nothing has changed, leading to a decrease in performance. This issue can be solved by using the useMemo hook, which allows you to memoize expensive calculations so that they are only recomputed when necessary.

 

But what is the useMemo Hook?

Basically, useMemo is a way to optimize your React code by memoizing expensive calculations. It takes two arguments: a function that does the calculation, and an array of dependencies. If any of the dependencies change, the function gets re-run. But if they don’t, the memoized value is returned instead.

 

So, what does that mean in plain English? Let’s say you have a component that displays a list of songs. Each time the component renders, it has to loop through the list and calculate the total length of all the songs. That’s a lot of work, especially if the list is long. But with useMemo, you can memoize that calculation so that it only runs when the list changes. That way, your UI stays fast and responsive.

 

An Example

Let’s take the song length example above. Without useMemo your code would probably look like

import React, {useEffect, useState} from "react";

const SongList = ({songs}) => {
    const [totalLength, setTotalLength] = useState(0);

    const calculateTotalLength = () => {
        let length = 0;
        songs.forEach(song => {
            length += song.length;
        });
        return length;
    };

    useEffect(() => {
        const length = calculateTotalLength();
        setTotalLength(length);
    }, [songs]);

    return (
        <div>
            <h2>Total Length: {totalLength}</h2>
            <ul>
                {songs.map(song => (
                    <li key={song.id}>
                        {song.title} ({song.length})
                    </li>
                ))}
            </ul>
        </div>
    );
};

While this code is not inherently bad, there are some considerations to keep in mind:

  • The calculateTotalLength function is called every time the component renders, even if the songs prop has not changed. This can be inefficient if the list of songs is long and the calculation is complex.
  • The useEffect hook updates the totalLength state every time the songs prop changes. While this is necessary for the component to display the correct total length, it can also cause unnecessary re-renders if other parts of the component are also dependent on the totalLength state.

 

A better approach using useMemo


import React, {useEffect, useMemo, useState} from "react";

const SongList = ({songs}) => {
    const [totalLength, setTotalLength] = useState(0);

    const memoizedTotalLength = useMemo(() => {
        let length = 0;
        songs.forEach(song => {
            length += song.length;
        });
        return length;
    }, [songs]);

    useEffect(() => {
        setTotalLength(memoizedTotalLength);
    }, [memoizedTotalLength]);

    return (
        <div>
            <h2>Total Length: {totalLength}</h2>
            <ul>
                {songs.map(song => (
                    <li key={song.id}>
                        {song.title} ({song.length})
                    </li>
                ))}
            </ul>
        </div>
    );
};

As you can see, the main difference here is the use of the useMemo hook to memoize the calculation of the total length. The calculation only runs when the songs prop changes, which helps to improve performance by avoiding unnecessary re-renders. The memoized value is then passed down to the useEffect hook to update the state of totalLength only when the memoized value changes.

Leave a Reply

Digital art dealers

Join our vibrant community of more than 750 members by subscribing to our newsletter. Every Monday, you'll receive a programming meme to kickstart your week.

follow us on

© 2023 Digital Art Dealers. All rights reserved.

%d bloggers like this: