# react-perf/jsx-no-new-array-as-prop

> Disallow arrays created during render as the value of a JSX prop

`[]` written inside a component makes a new array on every render. When you pass it as a prop, it's never equal to the value from the last render, so a child wrapped in `React.memo` renders again even though the contents are the same.

The rule reports array literals, `Array()`, `new Array()`, and calls to `.concat()`, `.map()` and `.filter()` with one argument. An array at the top level of a module isn't reported, because it's created once.

{/* Generated by src/codegen/lint-rule-docs.ts. Do not edit this section. */}

## Configure

Off by default. To turn it on:

```toml bunfig.toml
[lint.rules]
"react-perf/jsx-no-new-array-as-prop" = "error" # or "warn"
```

Every option, set to its default:

```toml bunfig.toml
[lint.rules]
"react-perf/jsx-no-new-array-as-prop" = ["error", {
  nativeAllowList = [], # list of strings
}]
```

{/* End of the generated section. */}

## Examples

Reported:

{/* bad */}
```jsx
function Settings() {
  return <Select options={["light", "dark"]} />;
}
```

{/* bad */}
```jsx
function Inbox({ messages }) {
  return <List items={messages.filter((message) => !message.read)} />;
}
```

The rule looks into `||`, `&&`, `??` and `? :`:

{/* bad */}
```jsx
function Inbox({ messages }) {
  return <List items={messages || []} />;
}
```

A variable declared inside the component has the same problem as an array written in the prop, and so does a destructured prop's default. The report is on the declaration:

{/* bad {"count": 2} */}
```jsx
function Inbox({ messages = [] }) {
  const columns = ["from", "subject"];
  return <List items={messages} columns={columns} />;
}
```

Not reported:

{/* good */}
```jsx
const themes = ["light", "dark"];
const none = [];

function Settings() {
  return <Select options={themes} />;
}

function Inbox({ messages }) {
  return <List items={messages || none} />;
}
```

If the array depends on props or state, cache it with `useMemo`:

{/* good */}
```jsx
import { useMemo } from "react";

function Inbox({ messages }) {
  const unread = useMemo(() => messages.filter((message) => !message.read), [messages]);
  return <List items={unread} />;
}
```

## Options

| Option | Default | What it does |
| --- | --- | --- |
| `nativeAllowList` | `[]` | Props to skip on elements with a lowercase name, such as `<div>`. A list of prop names (case doesn't matter), or `"all"` for every prop. |

With `{ "nativeAllowList": ["points"] }`, this is allowed:

{/* good {"options": [{"nativeAllowList": ["points"]}]} */}
```jsx
function Report() {
  return <my-chart points={[1, 2, 3]} />;
}
```

Components are still checked:

{/* bad {"options": [{"nativeAllowList": ["points"]}]} */}
```jsx
function Report() {
  return <Chart points={[1, 2, 3]} />;
}
```

## When not to use it

A new prop value only matters to a child that compares its props, for example with `React.memo`. The React Compiler memoizes these values for you.
