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

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

A function written inside a component is a new function 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 function does the same thing.

The rule reports arrow functions, function expressions, `.bind()` calls, `Function()` and `new Function()`. A function 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-function-as-prop" = "error" # or "warn"
```

Every option, set to its default:

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

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

## Examples

Reported:

{/* bad */}
```jsx
function Editor({ save }) {
  return <Button onClick={() => save("draft")} />;
}
```

{/* bad */}
```jsx
class Editor extends React.Component {
  render() {
    return <Button onClick={this.save.bind(this)} />;
  }
}
```

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

{/* bad */}
```jsx
function Editor({ onSave }) {
  return <Button onClick={onSave || (() => {})} />;
}
```

A function declared inside the component has the same problem as one written in the prop. The report is on the declaration:

{/* bad {"count": 2} */}
```jsx
function Editor({ save }) {
  const saveDraft = () => save("draft");
  function publish() {
    save("public");
  }
  return <Buttons onSave={saveDraft} onPublish={publish} />;
}
```

Not reported:

{/* good */}
```jsx
function reload() {
  location.reload();
}

function Editor() {
  return <Button onClick={reload} />;
}
```

If the function uses props or state, cache it with `useCallback`:

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

function Editor({ save }) {
  const saveDraft = useCallback(() => save("draft"), [save]);
  return <Button onClick={saveDraft} />;
}
```

In a class, make the handler a property and pass that:

{/* good */}
```jsx
class Editor extends React.Component {
  save = () => {
    this.props.save("draft");
  };

  render() {
    return <Button onClick={this.save} />;
  }
}
```

## Options

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

A DOM element doesn't compare its props to skip a render, so a new function costs nothing there. With `{ "nativeAllowList": "all" }`, this is allowed:

{/* good {"options": [{"nativeAllowList": "all"}]} */}
```jsx
function Editor({ save }) {
  return <button onClick={() => save("draft")}>Save</button>;
}
```

Components are still checked:

{/* bad {"options": [{"nativeAllowList": "all"}]} */}
```jsx
function Editor({ save }) {
  return <Button onClick={() => save("draft")} />;
}
```

## 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.
