Skip to content

eslint-config: turn off react-perf/* and react/jsx-props-no-spreading by default #1085

Description

@prisis

The react-perf rules and react/jsx-props-no-spreading fire heavily on modern React codebases without pointing at real defects. Proposing they be disabled by default in the React preset.

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

These rules predate the React Compiler. Their whole purpose is to stop inline objects and functions from breaking referential equality and causing re-renders — which is exactly what the compiler now memoises automatically.

Worse, they push in the opposite direction to the compiler: satisfying them means hand-rolling useMemo/useCallback, and manual memoisation can make the compiler bail on the component entirely rather than optimise it. So following the rule can measurably reduce optimisation.

They also collide with animation libraries, where prop objects are the API:

<m.div
    animate={{ opacity: 1, rotate: 0, scale: 1 }}
    initial={{ opacity: 0, rotate: -180, scale: 0.95 }}
    transition={{ damping: 20, stiffness: 200, type: "spring" }}
/>

Every one of those three props is a violation. In one app in this org these two rules alone produced 211 of 1027 problems (~21%), essentially all of them Motion props, with no genuine performance finding among them.

react/jsx-props-no-spreading

{...props} is the standard composition pattern for Radix / shadcn-style primitives — a wrapper forwards the underlying element's full prop surface:

const Tabs = ({ className, ref, ...properties }: TabsProperties) => (
    <TabsPrimitive.Root className={cn("flex flex-col gap-2", className)} ref={ref} {...properties} />
);

Complying means enumerating every prop of every primitive by hand and re-doing it whenever the upstream library changes. Same app: 49 violations, all in UI primitives.

Suggested change

Default these off in the React preset, with a comment explaining why, and let consumers opt back in:

// The React Compiler memoises component output, so these flag library prop
// objects (Motion animate/initial/transition) with no benefit — and satisfying
// them via manual memoisation can stop the compiler optimising the component.
"react-perf/jsx-no-new-object-as-prop": "off",
"react-perf/jsx-no-new-function-as-prop": "off",
"react-perf/jsx-no-new-array-as-prop": "off",
"react-perf/jsx-no-jsx-as-prop": "off",

// Radix/shadcn-style primitives compose by forwarding the full prop surface.
"react/jsx-props-no-spreading": "off",

Worth also considering whether react-x/no-unstable-context-value and react/jsx-no-constructed-context-values belong in the same group for compiler-enabled projects.

Happy to open a PR if the direction looks right.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions