What is React Memo? How to use React.memo()

·10 min read

What is React Memo? How to use React.memo()

Introduction

Often times as a React developer we need to focus on the application’s optimization and performance improvements. There are multiple ways you can archive a blazing-fast React app performance from third-party tools to native features.

One of the most commonly used techniques is to memoize the code we write for a React component and React Memo allows us to do just that! When applied correctly, you get no unnecessary re-renders thereby improving the responsiveness of our app.

In this article, you will get to know everything you need to know about React Memo with some examples and demos included. 

 

 

What is React Memo?

React Memo is a Higher Order Component (HOC) which itself wraps around a component to memoize the rendered output and skips unnecessary renderings.

The component around which it’s used will generate a memoized or an optimal version of it to speed up the render process. As you can see by now, it’s all done to improve the overall stability and rendering performance of your React application.

Also, it allows the component to check the old props against new ones to see if the value has changed or not.

Let’s get to know something more about it in the following points:

  • It’s a Higher Order Component: which means that by nature, it is a function that takes a component and then returns a new component.
  • Useful when you expect the same result from a component: you should wrap a component in your React app to React Memo when you know beforehand that it will render the same result to the DOM when given the same props to it. Thereby, it will result in a performance boost as it will memoize the result.
  • Uses the last rendered result: as the component is now memoized, therefore React will skip rendering it and reuse the last rendered result of it.
  • Only checks for prop changes: this means that if the props are passed down to the component changes, then only a new render will occur. If the props remain the same, you will always get the memoized result.
  • Effect on React Hooks: if your component uses Hooks like useState, useReducer, or useContext then, it will still re-render whenever the state or the context of the component changes.

 

 

Where to use React Memo? 

It’s very easy to start using this memoization technique to a majority of your components in the application. But we should know beforehand that this method only exists as a performance optimization

Here are some important points to note on where to use them:

  • Use it if you are using a pure functional component: this means that your component is not using classes and given the same props, it always renders the same output.
  • Use it when you know beforehand that a component will render quite often.
  • Use it if the re-rendering is done using the same props given to the component. If by any chance the props change, then it’s not a right idea to use memoization here.
  • Use it if your component is big enough to have props equality check done by React with a decent number of UI elements. Very short components with just a single heading won’t do justice.

 

Now let’s take a closer look at point number 3 above with an example.

This is one of the best use cases for React Memo. Usually, in your React apps, you can see that a situation occurs that makes a component render with the same props being forced to render by a parent component. 

For example, below you can see a parent component called SongsViews which essentially displays the number of views for a song in an application:

function SongsViews({ title, genre, viewCount }) {
 return (
   <div>
     <Song title={title} genre={genre} />Views: {viewCount}
   </div>
 );
}

Make sure you notice that:

  • We made it a functional component, not a class component.
  • We passed on three props to it: title, genre, and viewCount.

 

In a practical sense, here’s how it will render:

// Initial render
<SongsViews
 viewCount={0}
 title="My Song"
 genre="Pop"
/>

// After some seconds, views is 40
<SongsViews
 viewCount={40}
 title="My Song"
 genre="Pop"
/>

// After 10 minutes, views is 250
<SongsViews
 viewCount={250}
 title="My Song"
 genre="Pop"
/>

As you can see, whenever the viewCount prop is updated with a new value, the parent component SongViews renders. With this, the child component of Song is also triggered to render even if the other two props of title and genre remain the same throughout!

Hence, here we get a perfect case to apply some memoization on the child Song component so that useless re-rendering is prevented thereby improving the overall performance of the app.

 

 

Where NOT to use React Memo? 

Now that we know when we would be using React Memo, we should also consider the case where we should avoid using it without any context or overusing it. 

In a nutshell, you should not use React Memo in all React components that implement the shouldComponentUpdate() method. This is because, by default, it returns true always. The render change that occurs by using React Memo is the same implementation of the shouldComponentUpdate() method which essentially does the shallow comparison of the state and the props.

Other than that, these two cases should also be considered:

  • Don’t use React Memo if the component isn’t heavy and renders with different props altogether.
  • Wrapping a class-based component in React Memo is undesirable and therefore should not be used. Instead, you can extend PureComponent or implement shouldComponentUpdate() method.

 

 

Use React Memo in your application

Now that you know all about React Memo, let’s dive into creating a React application that actually uses it. But first, take a look at its syntax:

const MyComponent = React.memo(function MyComponent(props) {
  /* render using props */
});

As you can see, we wrap the component to memoize with React.memo(). Now let’s make a quick demo app to show the use case of memoization in React. 

 

Step 1: Create a new React app

Make sure you have Node.js installed on your system and then run the following commands:

npx create-react-app react-memo-demo
cd react-memo-demo
npm start

This will bootstrap a new React application and run the default app on http://localhost:3000/ in your default browser thanks to the Create React App tool.

Now let’s open the App.js file and remove all the code we have here. We will start coding from scratch a very basic to-do list app.

 

Step 2: Make the app interface

Our app will have:

  • An input field where users can type a new to-do item
  • A button to handle the click event which further adds new to-do items to a list
  • Then finally the actual list of items

Here’s the JSX code we need to return for the above elements:

return (
   <div>
     <input type="text" value={text} onChange={handleText} />
     	<button type="button" onClick={handleAddTodo}>
       <span role="img" aria-label="add emojie">
         ➕
       </span>
       Add todo
     </button>

<Todo list={todo} />
   </div>
 );

As you can see we also added necessary attributes to the input field with value and onChange which gets the text value typed by the user and change event(s) occurring on the input field respectively.

For the button, we simply have an onClick handler attached to it which we call handleAddTodo.

Lastly to render the list of items we don’t use the unordered list tag here as we are using a component called <Todo /> to get the list items by passing the list attribute to it.

 

Step 3: Create default state, handlers, and components 

To handle the state of our app we will be using the useState() Hook here. Let’s make a functional component called App() which uses useState() to initialize our app with two default values of to-do items “Shop groceries 🛒” and “Do yoga 🧘” as follows:

const [todo, setTodo] = React.useState([
   { title: "Shop groceries 🛒" },
   { title: "Do yoga 🧘" }
 ]);

 

Also, let’s use useState() again to initialize the text variable (which gets the actual value) for the input field as:

 const [text, setText] = React.useState("");

 

Next, we got our two handler functions. Let’s deal with them. The first one is handleText() which simply sets the value present in the input field:

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

 

The second one is handleAddTodo() which will be used to combine the array value (with concat()) and put it as a title text string value on the list:

const handleAddTodo = () => {
   setTodo(todo.concat({ title: text }));
 };

 

We have the <Todo /> component ready. Let’s pass on the list param to it and return an <ul> item which maps over the individual item to render a new <TodoItem /> child component:

const Todo = ({ list }) => {
  return (
   <ul>
     {list.map((item) => (
       <TodoItem item={item} />
     ))}
   </ul>
 );
};

 

As for this new child component, it will simply be returning the <li> item with list title to display after mapping:

const TodoItem = ({ item }) => {
 return <li>{item.title}</li>;
};

 

At this point, your code should look like the following:

import React from "react";

const App = () => {
 const [todo, setTodo] = React.useState([
   { title: "Shop groceries 🛒" },
   { title: "Do yoga 🧘" }
 ]);

 const [text, setText] = React.useState("");

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

 const handleAddTodo = () => {
   setTodo(todo.concat({ title: text }));
 };

 return (
   <div>
     <input type="text" value={text} onChange={handleText} />
     <button type="button" onClick={handleAddTodo}>
       <span role="img" aria-label="add emojie">
         ➕
       </span>
       Add todo
     </button>

     <Todo list={todo} />
   </div>
 );
};

const Todo = ({ list }) => {
  return (
   <ul>
     {list.map((item) => (
       <TodoItem item={item} />
     ))}
   </ul>
 );
};

const TodoItem = ({ item }) => {
  return <li>{item.title}</li>;
};

export default App;

The app should also look and work like this:

React memo example app

At this point in time, we successfully made a dead-simple to-do app using Hooks. Adding 3-4 items is fine. But what if our list was huge like hundreds or thousands of items? Maybe our app was using this list to render items fetched by an external database or API? 

Then we need to take care of performance improvements so that our app doesn’t feel slow to use as it will be rendering multiple components and elements!

 

Step 4: Optimizing the components with React Memo

Let’s switch gears to memoizing some of the useful components. The first is the <Todo /> component. Wrap it around React.memo like this:

// Memoized Todo component

const Todo = React.memo(({ list }) => {
 console.log("Render: Todo");
 return (
   <ul>
     {list.map((item) => (
       <TodoItem item={item} />
     ))}
   </ul>
 );
});

With this, only the <App /> component will re-render because it's the only component that is affected by the change of state. The <Todo /> component’s state doesn’t change hence, it doesn’t do unnecessary renders improving app performance. 

 

By default, when the to-do list changes it causes the <Todo /> component to update. Now let’s take it a step further by rendering only the newly added item to the list instead of all items at once by memoizing the <TodoItem /> child component as follows:

const TodoItem = React.memo(({ item }) => {
 return <li>{item.title}</li>;
});

Now all the previous to-dos will remain the same and won’t re-render. What will actually re-render are all of the components affected by the state change.

 

Let’s see the memoization effect in action by introducing some log statements after the <App />, <Todo /> and <TodoItem /> components as such:

// App component
const App = () => {
 console.log("App component render");
.
.
.
// Todo component
const Todo = React.memo(({ list }) => {
 console.log("Todo component render");
.
.
.

// TodoItem component
const TodoItem = React.memo(({ item }) => {
 console.log("TodoItem component render");
.
.
.

By doing this we get to know when each of them renders while we add new to-do items. Now if we open our browser’s console pane we can see the following:

React memo example app with console

As we can see both the <Todo /> and <TodoItem /> components render only once which is why we used React Memo here!

 

 

Conclusion

React Memo is one of the most useful tools when it comes to optimizing the performance of your React components. If we use it correctly (and not over-use it), then it can impact the interaction of our app to a great extent. The effect is mostly seen on larger applications that consume more data.

Of course, we can’t use it everywhere, and also React doesn’t apply it to its default starter project because under the hood the React.memo() function has to compare the previous props with the new props to decide whether to re-render or not. 

From here, you can read the following topics to better understand React Memo: