Skip to main content

jsx-no-new-object-as-prop

Disallow render-local object allocations passed through JSX props.

Deprecated

  • Lifecycle: Deprecated, frozen, and non-recommended.
  • Deprecated since: v3.0.0
  • Available until: v4.0.0
  • Use instead: no-unstable-react-values

The replacement consolidates JSX, function, array, and object prop stability checks behind one rule and one intrinsic-element policy. Do not enable both.

Targeted pattern scope

This rule reports object literals and unshadowed Object() or new Object() allocations used as JSX prop values inside a function or class render scope. Object calls are reported only when they have no argument or a statically primitive argument; an unknown or object-valued argument may be returned unchanged. The rule follows logical and conditional branches and resolves a single same-function const initializer.

Module constants and mutable bindings are not traced. Intrinsic JSX attributes can be exempted by name; custom-component props remain in scope.

What this rule reports

A fresh object reference can defeat shallow prop comparisons or retrigger identity-sensitive consumers. Creating an object during render is otherwise ordinary JavaScript and is not automatically a defect.

Why this rule exists

Object identity is observable by shallow comparisons, dependency arrays, and some component APIs. The rule highlights new identities where a project has chosen to make that cost explicit.

❌ Incorrect

function Card() {
return <Panel options={{ dense: true }} />; // New object identity every render.
}
function Card() {
const options = { dense: true };
return <Panel options={options} />; // The local const does not make it stable.
}

✅ Correct

const panelOptions = { dense: true };

function Card() {
return <Panel options={panelOptions} />;
}
function Card({ options }: { options: PanelOptions }) {
return <Panel options={options} />;
}

Behavior and migration notes

This rule reports only. Hoisting an object or adding useMemo can be wrong when its properties depend on render inputs.

React Compiler can automatically memoize values and components in supported builds. Enable this opt-in rule only for boundaries where stable identity is intentional and measured. It is included by both the all and allStrict presets.

Options

interface Options {
nativeAllowList?: "all" | readonly string[];
}

Default: { nativeAllowList: "all" }

nativeAllowList ignores case-insensitive attribute names on intrinsic JSX elements. The default "all" keeps the rule focused on component props because intrinsic attributes do not participate in a child component's prop-identity contract. Set it to [] to check every intrinsic attribute, or provide selected names to ignore.

// config: { nativeAllowList: ["style"] }
function Card() {
return <section style={{ display: "grid" }} />; // Allowed intrinsic attribute.
}

ESLint flat config example

import etcMisc from "eslint-plugin-etc-misc";

export default [
{
plugins: { "etc-misc": etcMisc },
rules: {
"etc-misc/jsx-no-new-object-as-prop": "warn",
},
},
];

When not to use it

Disable this rule when consumers do not rely on prop identity, when inline objects improve clarity without measured cost, or when React Compiler owns memoization.

Package documentation

The rule is a clean-room implementation informed by eslint-plugin-react-perf. This implementation does not generate memoization fixes.

Rule catalog ID: R019

Further reading

Adoption resources

  • Start at warning level in CI, then move to error after cleanup.
  • Review whether stable identity is observable before lifting or memoizing values.