DEV Community

Manoj Kumar Patra
Manoj Kumar Patra

Posted on

1

Using React.memo

# Definition

React.memo

  • A higher order component that can be used to get some performance boost if a component renders the same results given the same props
  • Checks for prop changes, and skips rendering the component, and reuse the last rendered result in case previous and current props are the same

function PizzaComponent({ name, price }) {
  /* render using props */
  return (
    <div>Pizza: {name}</div>
    <div>Total: ${price}</div>
  )
}

export default React.memo(PizzaComponent);

Enter fullscreen mode Exit fullscreen mode

This component is a candidate for memoization as given a πŸ• image, it always renders the same πŸ• details.

  • By default, it does a shallow comparison of props
  • For custom control on props comparison, a custom comparison function can be provided as a second argument.

Let's extend our PizzaComponent to also show different toppings available for a πŸ•. Toppings will be an array of strings. As mentioned above, React.memo does a shallow comparison of props, so, in this case, even though the toppings array remains same, it will still re-render.

So, how do we fix this?

We pass a custom comparison function as follows:


function PizzaComponent({ name, price, toppings }) {
  function areEqual(prevProps, nextProps) {
    /*
    return true if passing nextProps to render would return
    the same result as passing prevProps to render,
    otherwise return false
    */
    return (
      prevProps.name === nextProps.name,
      prevProps.price === nextProps.price,
      prevProps.toppings.every(topping => nextProps.toppings.includes(topping))
    )
  }

  /* render using props */
  return (
    <div>Pizza: {name}</div>
    <div>Total: ${price}</div>
    {toppings.map((topping, index) => (
      <div key={`${name}_${topping}`}>{topping}</div>
    ))}
  )
}

export default React.memo(PizzaComponent, areEqual);

Enter fullscreen mode Exit fullscreen mode

# Using React memo

Use React.memo to get a performance boost when:

  1. Component re-renders often
  2. Component is usually provided with the same props during re-rendering
  3. Component contains a relevant amount of elements to reason props equality check

If a component with hooks is wrapped with React.memo, then it will still re-render when state or context changes.

# React memo with function as props

Let's add the functionality to order a πŸ• in our PizzaComponent called onOrder as follows:


function PizzaComponent({ name, price, toppings, onOrder }) {
  function areEqual(prevProps, nextProps) {
    /*
    return true if passing nextProps to render would return
    the same result as passing prevProps to render,
    otherwise return false
    */
    return (
      prevProps.name === nextProps.name,
      prevProps.price === nextProps.price,
      prevProps.toppings.every(topping => nextProps.toppings.includes(topping))
    )
  }

  /* render using props */
  return (
    <div>Pizza: {name}</div>
    <div>Total: ${price}</div>
    {toppings.map((topping, index) => (
      <div key={`${name}_${topping}`}>{topping}</div>
    ))}
    <button onClick={onOrder}>Order</button>
  )
}

export default React.memo(PizzaComponent, areEqual);

Enter fullscreen mode Exit fullscreen mode

and let's use it as follows:


function App ({ store }) {
  const { pizza } = store;
  return (
    <PizzaComponent
      name={pizza.name}
      price={pizza.price}
      toppings={pizza.toppings}
      onOrder={() => placeOrder(pizza.price, pizza.coupon)}
    />
  )
}

Enter fullscreen mode Exit fullscreen mode

Since, React.memo does a shallow comparison, this will do a re-render everytime as it will see the callback function onOrder as a new prop everytime.

To fix this, we can wrap the function passed to onOrder with useCallback as follows:


function App ({ store }) {
  const { pizza } = store;
  /**
   * This will always return the same function instance as long as pizza is the same.
   */
  const onOrder = useCallback(
    () => placeOrder(pizza.price, pizza.coupon),
    [pizza],
  );

  return (
    <PizzaComponent
      name={pizza.name}
      price={pizza.price}
      toppings={pizza.toppings}
      onOrder={onOrder}
    />
  )
}

Enter fullscreen mode Exit fullscreen mode

Heroku

Deliver your unique apps, your own way.

Heroku tackles the toil β€” patching and upgrading, 24/7 ops and security, build systems, failovers, and more. Stay focused on building great data-driven applications.

Learn More

Top comments (0)

Image of Quadratic

Free AI chart generator

Upload data, describe your vision, and get Python-powered, AI-generated charts instantly.

Try Quadratic free

πŸ‘‹ Kindness is contagious

Value this insightful article and join the thriving DEV Community. Developers of every skill level are encouraged to contribute and expand our collective knowledge.

A simple β€œthank you” can uplift someone’s spirits. Leave your appreciation in the comments!

On DEV, exchanging expertise lightens our path and reinforces our bonds. Enjoyed the read? A quick note of thanks to the author means a lot.

Okay