Using React.memo
Tags: frontend, typescript, react
Published: 2022-09-10 04:51:12

---
title: 'Using React.memo'
metaTitle: 'Using React.memo'
metaDesc: 'Using React.memo'
tags:
  - frontend
  - typescript
  - react
---

## [#](#definition) 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

```typescript

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

export default React.memo(PizzaComponent);

```

This component is a candidate for memoization as given a :pizza: image, it always renders the same :pizza: 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 :pizza:. 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:

```typescript

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);

```

## [#](#using-react-memo) 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) React memo with function as props

Let's add the functionality to order a :pizza: in our `PizzaComponent` called `onOrder` as follows:

```typescript

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);

```

and let's use it as follows:

```typescript

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

```

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:

```typescript

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}
    />
  )
}

```