Skip to main content
interlace
Plugin: react-featuresRules

react-render-optimization

Report inline object, array and function props passed to a component that compares props by identity, and props computed by expensive expressions.

Quick Summary

AspectDetails
SeveritySuggestion (performance)
Auto-FixNo (suggestions: useMemo / useCallback)
CategoryPerformance
Best ForComponents that use memo or PureComponent

Rule Details

Inline props

An object literal, an array literal (detectInlineProps) or an inline function (detectInlineFunctions) written as a prop has a new identity every render. That costs a re-render only when the receiver skips re-rendering on equal props: a component the file wraps in React's memo (any spelling, including memo(forwardRef(...))) or a class extending React's PureComponent. The rule reports those.

It does not report a host element (<div style={{…}}>): React sets the new value on the DOM node and there is no render to save. Nor a component the file defines without memo (a function, an arrow, forwardRef(...), a Component class): it re-renders with its parent whatever its props are.

A conditional whose two branches are both fresh values of the same kind is a fresh value; TypeScript's as, satisfies and ! are seen through.

Expensive computations

With detectExpensiveComputations, a prop expression is reported as expensive when its estimated complexity reaches minComputationComplexity: a loop counts 3, a call or a conditional 1, measured on the expression and up to five enclosing nodes. This is an estimate, not a measurement.

Options

OptionTypeDefaultDescription
detectInlinePropsbooleantrueReport inline object / array props.
detectInlineFunctionsbooleantrueReport inline function props.
detectExpensiveComputationsbooleantrueReport props whose estimated complexity is high.
minComputationComplexitynumber3Complexity at which a prop expression is reported.
ignoreInTestsbooleantrueSkip *.test.* / *.spec.* files.

Examples

❌ Incorrect

const Chart = memo(function Chart({ options }: Props) {
  /* … */
});

function Dashboard() {
  // A new object every render: Chart's memo never holds.
  return <Chart options={{ stacked: true }} />;
}

✅ Correct

const CHART_OPTIONS = { stacked: true };

function Dashboard() {
  return <Chart options={CHART_OPTIONS} />;
}

// A host element has no render to save.
<div style={{ display: 'flex' }} />;

Known False Positives

  • A component the file cannot see (an import, <Ctx.Provider>) is still checked for inline props: whether it compares props by identity is unknown.
  • Expensive computations are an estimate from node counts, not a measurement.

Further Reading

Use this rule

npm install -D oxlint-plugin-react-features
.oxlintrc.json
{  "jsPlugins": ["oxlint-plugin-react-features"],  "rules": {    "react-features/react-render-optimization": "error"  }}
vite.config.ts
import { defineConfig } from 'vite-plus';export default defineConfig({  lint: {    jsPlugins: ['oxlint-plugin-react-features'],    rules: {      'react-features/react-render-optimization': 'error',    },  },});

oxlint-plugin-react-features re-exports eslint-plugin-react-features/oxlint: the same rules under the same IDs, and no ESLint install. Why oxlint.

Did this rule catch something? Star the repo to get new CWE coverage as we ship it — or follow the AI-code-security benchmarks behind these rules.