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

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

Also called react_perf/jsx-no-new-array-as-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.

Configure#

Off by default. To turn it on:

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

Every option, set to its default:

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

Examples#

example.jsx1 problem
function Settings() {
  return <Select options={["light", "dark"]} />;
}
example.jsx1 problem
function Inbox({ messages }) {
  return <List items={messages.filter((message) => !message.read)} />;
}

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

example.jsx1 problem
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:

example.jsx2 problems
function Inbox({ messages = [] }) {
  const columns = ["from", "subject"];
  return <List items={messages} columns={columns} />;
}
example.jsxNo problems
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:

example.jsxNo problems
import { useMemo } from "react";

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

Options#

OptionDefaultWhat 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:

example.jsxwith { "nativeAllowList": ["points"] }No problems
function Report() {
  return <my-chart points={[1, 2, 3]} />;
}

Components are still checked:

example.jsxwith { "nativeAllowList": ["points"] }1 problem
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.