Skip to main content
interlace
Plugin: react-featuresRules

react-no-inline-functions

react-no-inline-functions rule

Prevent inline functions in React renders with performance metrics. This rule is part of eslint-plugin-react-features and provides LLM-optimized error messages with fix suggestions.

💡 Provides suggestions | 🔧 Automatically fixable

Quick Summary

AspectDetails
SeverityWarning (performance best practice)
Auto-Fix✅ Yes (suggests useCallback)
CategoryReact / Performance
ESLint MCP✅ Optimized for ESLint MCP integration
Best ForReact/Next.js applications, performance-critical components

Rule Details

An inline function written as a prop (onSelect={() => …}, a function expression, or a choice between two) is a new function on every render. It 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. A function child (<Loader>{(data) => …}</Loader>) is the children prop and is judged the same way.

It does not report:

  • a host element (<button onClick={() => …}>, <my-widget>): React updates the DOM listener; there is no render to save;
  • 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 callback passed to a call ({items.map((item) => <li … />)}, onSelect={debounce(() => …)}): it is not itself a prop;
  • a function passed by reference (onSelect={handleSelect}).

Configuration

OptionTypeDefaultDescription
allowInEventHandlersbooleanfalseAllow inline functions in event-handler props: on + a capital letter (onClick), React's naming. only or renderItem is not one.
minArraySizenumber5Accepted for compatibility; has no effect (the size of an array is not known statically).

Examples

❌ Incorrect

function TodoList({ todos }: Props) {
  return (
    <div>
      {todos.map((todo) => (
        <TodoItem
          key={todo.id}
          todo={todo}
          onDelete={() => deleteTodo(todo.id)}  // ❌ Inline function
        />
      ))}
    </div>
  );
}

✅ Correct

function TodoList({ todos }: Props) {
  const onDelete = useCallback((id: string) => deleteTodo(id), []);
  return todos.map((todo) => (
    <TodoItem key={todo.id} todo={todo} onDelete={onDelete} />
  ));
}

// A host element has no render to save.
<button onClick={() => save()}>Save</button>;

Configuration Examples

ESLint 9+ (Flat Config)

import reactFeatures from 'eslint-plugin-react-features';
import type { ReactNoInlineFunctionsOptions } from 'eslint-plugin-react-features/types';

const inlineConfig: ReactNoInlineFunctionsOptions = {
  allowInEventHandlers: true, // Allow simple event handlers
  minArraySize: 5, // Only warn for large lists
};

export default [
  {
    plugins: {
      'react-features': reactFeatures,
    },
    rules: {
      'react-features/react-no-inline-functions': ['warn', inlineConfig],
    },
  },
];

ESLint 8 (Legacy Config with JSDoc Types)

/** @type {import('eslint-plugin-react-features/types').ReactNoInlineFunctionsOptions} */
const inlineConfig = {
  allowInEventHandlers: true, // Allow simple event handlers
  minArraySize: 5, // Only warn for large lists
};

module.exports = {
  plugins: ['react-features'],
  rules: {
    'react-features/react-no-inline-functions': ['warn', inlineConfig],
  },
};

For more examples and patterns, see the package README.

Performance Impact

Array SizeRe-rendersImpact
1-10Low🟢 Minor
11-100Medium🟡 Moderate
100+High🔴 Significant

Comparison with Alternatives

Featurereact-no-inline-functionseslint-plugin-reactreact-hooks/exhaustive-deps
Inline Function Detection✅ Yes⚠️ Limited❌ No
Performance Metrics✅ Yes❌ No❌ No
Auto-Fix✅ Yes❌ No❌ No
LLM-Optimized✅ Yes❌ No❌ No
ESLint MCP✅ Optimized❌ No❌ No
useCallback Suggestions✅ Yes❌ No⚠️ Limited

Further Reading

Known False Positives

  • A component the file cannot see (an import such as TodoItem above, or a member such as <Ui.Row>) is still checked: whether it compares props by identity is unknown, so the finding may not hold.

Known False Negatives

  • A fresh function produced by a call (onSelect={debounce(() => …)}, onSelect={handler.bind(this)}) is not followed.

Use this rule

npm install -D oxlint-plugin-react-features
.oxlintrc.json
{  "jsPlugins": ["oxlint-plugin-react-features"],  "rules": {    "react-features/react-no-inline-functions": "error"  }}
vite.config.ts
import { defineConfig } from 'vite-plus';export default defineConfig({  lint: {    jsPlugins: ['oxlint-plugin-react-features'],    rules: {      'react-features/react-no-inline-functions': '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.