DEV Community

Paramanantham Harrison
Paramanantham Harrison

Posted on • Originally published at learnwithparam.com

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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>
  )
}
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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 🙌

Top comments (0)