How to Use useMemo Hook in React?
How to Use useMemo Hook in React?

Hello and welcome back to the channel. In this video you will learn one of the important React hooks and it's useMemo. It's really nice for performance optimisations so let's jump right into it.

Here I have empty create-react-app project where we can directly start writing code. If you don't know how to generate react project with create-react-app I made a video on that so go check it out first.

I you can see in browser I have just a single h1 tag and it's our App.js component. Let's have a look. So it's a normal stateless React component with markup inside.

As we are using React bigger than 16 version (actually 17) we can use hooks inside without installing any additional packages.

It will be much easier to understand how useMemo works by real example so let's create a list of users, an input and a search button.

const users = [
  { id: "1", name: "Foo" },
  { id: "2", name: "Bar" },
];

function App() {
  const [text, setText] = React.useState("");
  const [search, setSearch] = useState("");

  const handleText = (event) => {
    setText(event.target.value);
  };

  const handleSearch = () => {
    setSearch(text);
  };

  return (
    <div>
      <h1>React hooks for beginners</h1>
      <input type="text" value={text} onChange={handleText} />
      <button type="button" onClick={handleSearch}>
        Search
      </button>
    </div>
  );
}

So we created an array of initial users on the top. Also we have 2 states, one for changed text in the input and other we are setting only when we click on the button. This is the crucial difference.

Now we want to search for users so we will render only filtered by search users.

function App() {
  ...
  const filteredUsers = users.filter((user) => {
    console.log("filtering users");
    return user.name.toLowerCase().includes(search.toLowerCase());
  }),

  return (
    <div>
      <h1>React hooks for beginners</h1>
      <input type="text" value={text} onChange={handleText} />
      <button type="button" onClick={handleSearch}>
        Search
      </button>
      <ul>
        {filteredUsers.map((filteredUser) => (
          <div key={filteredUser.id}>{filteredUser.name}</div>
        ))}
      </ul>
    </div>
  );
}

As you can see in browser now our users are rendered and when we click search button they are filtering correctly and rendering on the screen. But what problem do we have here? As you can see each letter that we are typing leads to rerendering of the component. Which is fine. But rerendering means that every line inside component will be called from beginning to the end. And this is exactly what happens. This is why every time when we are typing we see our console log inside filtering of users. Because we are calling this filtering again and again.

The problem here is obvious. If we have lots of data in array (like 1000 or users) then it is not good for performance because we are doing filter with exactly same data because actually our search value didn't change.

This is exactly where useMemo comes into play. It brings the idea of memoization. This means that if value didn't change then we just store the result of some slow computed function in the variable and use it until our variables don't change. As you see our users filter depends only on search.

const filteredUsers = useMemo(
  () =>
    users.filter((user) => {
      console.log("filtering users");
      return user.name.toLowerCase().includes(search.toLowerCase());
    }),
  [search]
);

So we just put our filter as a return of useMemo. Also we set a dependencies array. It works the same way as in useEffect. Our useMemo will call the function only when search changes.

As you can see in browser now our filtering is not triggered when we are typing but only when we click on submit button.

It's also super important to remember that if you forget to write a dependency array or it is empty your useMemo function is doing nothing. So it is crucial to provide a dependency array.

Also you might ask why we don't write the every line and constuction with useMemo if it's so effective. Because every optimisation comes at a cost and calling useMemo and storing value additionally all consumes performance. So it is recommended to use memo only when you have performance problem or you know that exactly here it will be the bottleneck.

So this is how you can use useMemo hook. But I always recommend to minimise it's usage and not to do optimisations until you have problems.

If "React hooks for beginners" is too easy for you I have a full hooks course which is going 8 hours where we are creating real application from scratch. I will link it down in the description below.

📚 Source code of what we've done