> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/preactjs/preact/llms.txt
> Use this file to discover all available pages before exploring further.

# memo

> Memoize functional components in Preact to optimize rendering performance

# memo

Memoize a functional component so that it only re-renders when its props actually change. This was previously known as `React.pure`.

## Signature

```typescript theme={null}
function memo<P = {}>(
  component: FunctionalComponent<P>,
  comparer?: (prev: P, next: P) => boolean
): FunctionComponent<P>
```

<ParamField path="component" type="FunctionalComponent<P>" required>
  The functional component to memoize.
</ParamField>

<ParamField path="comparer" type="(prev: P, next: P) => boolean">
  Optional custom comparison function. Should return `true` if the props are equal (skip render), or `false` if they are different (re-render).

  If not provided, a shallow comparison is performed automatically.
</ParamField>

<ParamField path="returns" type="FunctionComponent<P>">
  A memoized version of the component that only re-renders when props change.
</ParamField>

## Usage

### Basic Memoization

Memoize a component with automatic shallow prop comparison:

```jsx theme={null}
import { memo } from 'preact/compat';

const ExpensiveComponent = memo(({ value, label }) => {
  console.log('Rendering ExpensiveComponent');
  
  return (
    <div>
      <strong>{label}:</strong> {value}
    </div>
  );
});

// This component will only re-render when value or label changes
```

### Custom Comparison

Provide a custom comparison function for complex props:

```jsx theme={null}
import { memo } from 'preact/compat';

const UserCard = memo(
  ({ user }) => (
    <div>
      <h3>{user.name}</h3>
      <p>{user.email}</p>
    </div>
  ),
  (prevProps, nextProps) => {
    // Return true if props are equal (skip render)
    return prevProps.user.id === nextProps.user.id &&
           prevProps.user.name === nextProps.user.name &&
           prevProps.user.email === nextProps.user.email;
  }
);
```

### Array Props

Compare array contents:

```jsx theme={null}
import { memo } from 'preact/compat';

const List = memo(
  ({ items }) => (
    <ul>
      {items.map(item => <li key={item.id}>{item.name}</li>)}
    </ul>
  ),
  (prevProps, nextProps) => {
    // Deep comparison of array contents
    if (prevProps.items.length !== nextProps.items.length) {
      return false;
    }
    
    return prevProps.items.every((item, index) => 
      item.id === nextProps.items[index].id
    );
  }
);
```

### With Hooks

Memo works seamlessly with hooks:

```jsx theme={null}
import { memo, useState, useCallback } from 'preact/compat';

const Counter = memo(({ onIncrement }) => {
  const [count, setCount] = useState(0);
  
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Local +1</button>
      <button onClick={onIncrement}>Parent +1</button>
    </div>
  );
});

function Parent() {
  const [value, setValue] = useState(0);
  
  // Memoize callback to prevent Counter from re-rendering
  const increment = useCallback(() => {
    setValue(v => v + 1);
  }, []);
  
  return <Counter onIncrement={increment} />;
}
```

## Implementation Details

The `memo` implementation in Preact:

```javascript theme={null}
export function memo(c, comparer) {
  function shouldUpdate(nextProps) {
    let ref = this.props.ref;
    let updateRef = ref == nextProps.ref;
    if (!updateRef && ref) {
      ref.call ? ref(null) : (ref.current = null);
    }

    if (!comparer) {
      return shallowDiffers(this.props, nextProps);
    }

    return !comparer(this.props, nextProps) || !updateRef;
  }

  function Memoed(props) {
    this.shouldComponentUpdate = shouldUpdate;
    return createElement(c, props);
  }
  
  Memoed.displayName = 'Memo(' + (c.displayName || c.name) + ')';
  Memoed.prototype.isReactComponent = true;
  Memoed.type = c;
  return Memoed;
}
```

### Key Features

1. **Shallow Comparison**: By default, uses `shallowDiffers` to compare props
2. **Custom Comparison**: Accepts optional custom comparison function
3. **Ref Handling**: Properly handles ref changes
4. **Display Name**: Automatically generates display name for debugging

## Comparison Logic

### Default Shallow Comparison

When no comparer is provided, `memo` performs a shallow comparison:

```javascript theme={null}
function shallowDiffers(a, b) {
  for (let i in a) if (i !== '__source' && !(i in b)) return true;
  for (let i in b) if (i !== '__source' && a[i] !== b[i]) return true;
  return false;
}
```

This checks if:

* Any keys exist in one object but not the other
* Any values differ using strict equality (`!==`)

### Custom Comparer Return Value

**Important**: The comparer function should return:

* `true` if props are **equal** (skip re-render)
* `false` if props are **different** (re-render)

This is the opposite of `shouldComponentUpdate`!

## Performance Considerations

### When to Use memo

✅ **Good use cases:**

* Components that render frequently with the same props
* Components with expensive render calculations
* List items in a large list
* Components receiving callback props from parent

❌ **Avoid memo when:**

* Props change on every render anyway
* Component is already fast
* The memo overhead outweighs render cost

### Measuring Performance

```jsx theme={null}
import { memo } from 'preact/compat';

const SlowComponent = ({ data }) => {
  console.time('SlowComponent render');
  
  // Expensive computation
  const result = expensiveCalculation(data);
  
  console.timeEnd('SlowComponent render');
  
  return <div>{result}</div>;
};

// Compare with and without memo
const MemoizedSlow = memo(SlowComponent);
```

## Type Definitions

```typescript theme={null}
type MemoExoticComponent<C extends FunctionalComponent<any>> =
  FunctionComponent<ComponentProps<C>> & {
    readonly type: C;
  };

export function memo<P = {}>(
  component: FunctionalComponent<P>,
  comparer?: (prev: P, next: P) => boolean
): FunctionComponent<P>;

export function memo<C extends FunctionalComponent<any>>(
  component: C,
  comparer?: (
    prev: ComponentProps<C>,
    next: ComponentProps<C>
  ) => boolean
): C;
```

## Checking if a Component is Memoized

```jsx theme={null}
import { isMemo } from 'preact/compat';

const MyComponent = memo(() => <div>Hello</div>);

console.log(isMemo(MyComponent)); // true
```

## Best Practices

1. **Profile First**: Use browser dev tools to identify slow components before memoizing
2. **Memoize Callbacks**: Combine with `useCallback` for callback props
3. **Memoize Values**: Use `useMemo` for computed values passed as props
4. **Custom Comparers**: Only use custom comparers when necessary - they add overhead
5. **Ref Stability**: Ensure ref callbacks are stable to avoid unnecessary updates

## Common Patterns

### Memoizing with Context

```jsx theme={null}
import { memo, useContext } from 'preact/compat';

const ThemedButton = memo(({ label }) => {
  const theme = useContext(ThemeContext);
  return <button className={theme}>{label}</button>;
});
```

### Memoizing List Items

```jsx theme={null}
import { memo } from 'preact/compat';

const ListItem = memo(({ item, onDelete }) => (
  <li>
    {item.name}
    <button onClick={() => onDelete(item.id)}>Delete</button>
  </li>
));

function List({ items }) {
  const handleDelete = useCallback((id) => {
    // delete logic
  }, []);
  
  return (
    <ul>
      {items.map(item => (
        <ListItem key={item.id} item={item} onDelete={handleDelete} />
      ))}
    </ul>
  );
}
```

## Source

Implementation: compat/src/memo.js:1-35
