React.memo helps you to avoid re-rendering of computationally heavy components

React.memo is useful when your component have some heavy computation or some expensive operations. It is similar to PureComponent but it works with functional components.

Let's say we have a component that renders a list of items. The list of items is passed as a prop to the component. The component renders the list of items as a list of <li> elements.

// BookList.js
const BookList = ({ items }) => (
  <ul>
    {items.map((item) => (
      <li key={item.id}>{item.name}</li>
    ))}
  </ul>
)

export default List

Now, let's say we have a parent component that renders the BookList component. The parent component has a state that contains the list of items. The parent component renders the BookList component with the list of items from the state.

// App.js
const App = () => {
  const [items, setItems] = useState([])

  useEffect(() => {
    fetch('/api/books')
      .then((res) => res.json())
      .then((data) => setItems(data))
  }, [])

  return <BookList items={items} />
}

export default App

Let's render the BookItem component for each item in the list. The BookItem component renders the details of the book. The BookItem component fetches the details of the book from the server when the component is mounted. The BookItem component renders the details of the book when the details are available.

// BookList.js
const BookList = ({ items }) => (
  <ul>
    {items.map((item) => (
      <BookItem key={item.id} item={item} />
    ))}
  </ul>
)

// BookItem.js
const BookItem = ({ item }) => {
  const [details, setDetails] = useState(null)

  useEffect(() => {
    fetch(`/api/books/${item.id}`)
      .then((res) => res.json())
      .then((data) => setDetails(data))
  }, [item.id])

  // Compute the average rating of the book
  // TODO: This can be optimized with useMemo, I will cover that in next article separately
  const averageRating = details
    ? details.reviews.reduce((acc, review) => acc + review.rating, 0) /
      details.reviews.length
    : null

  return (
    <li>
      <h3>{item.name}</h3>
      <p>{item.author}</p>
      <p>Average Rating: {averageRating}</p>
    </li>
  )
}

Fetching the details of the book is an expensive operation. We don't want to fetch the details of the book when the list of items is changed. We only want to fetch the details of the book when the component is mounted. We can use React.memo to avoid re-rendering of the BookItem component when the list of items is changed.

// BookList.js
const BookList = ({ items }) => (
  <ul>
    {items.map((item) => (
      <BookItem key={item.id} item={item} />
    ))}
  </ul>
)

// BookItem.js
const BookItem = ({ item }) => {
  const [details, setDetails] = useState(null)

  useEffect(() => {
    fetch(`/api/books/${item.id}`)
      .then((res) => res.json())
      .then((data) => setDetails(data))
  }, [item.id])

  // Compute the average rating of the book
  const averageRating = details
    ? details.reviews.reduce((acc, review) => acc + review.rating, 0) /
      details.reviews.length
    : null

  return (
    <li>
      <h3>{item.name}</h3>
      <p>{item.author}</p>
      <p>Average Rating: {averageRating}</p>
    </li>
  )
}

// Memoize the component to avoid re-rendering when the list of items is changed
export default React.memo(BookItem)

What if only few items in the list is changed?

It will re-render only the items that are changed. It will not re-render the items that are not changed.

When to use React.memo

  • Real time apps that updates frequently. Example: Sports tracker app that renders the details of a match live. The details of the match are fetched from the server. The details of the match are updated every few seconds. You can memoize the component to avoid re-rendering of the component when the details of the match are updated. It helps to consume less CPU and memory.
  • Apps that renders a list of items and updates it more frequently. Example: A chat app that renders the list of messages. The list of messages are updated frequently. You can memoize the component to avoid re-rendering of the component when the list of messages are updated.

When not to use React.memo

  • When the component is not expensive to render. Example: A component that renders a button. It is not expensive to render a button. You don't need to memoize the component. Pre-mature optimization is always evil 🤣
  • When the component is expensive to render but the component is not re-rendered frequently. Example: A component that renders a list of items. The list of items are fetched from the server. The list of items are not updated frequently. You don't need to memoize the component.

Hope you learned something new today 🤓. Keep learning and share your comments by tagging me on twitter @learnwithparam 🙌

Beginners to ProNode Js

Visual Guide to API Design Best Practices

This visual eBook covers essential best practices for designing robust APIs using REST principles.

This book is ideal for beginners and backend developers seeking to enhance their API design skills. However, it is not suited for those seeking an in-depth exploration of API design. This book is a quick read under 40 slides like scrolling through your instagram feed.

Visual Guide to API Design Best Practices