New
Introducing React Bench, see how different models perform on React code

react-doctor/preact-no-render-arguments

Drop render's positional params and read this.props / this.state inside render() instead

Validation prompt

Use this to decide whether a fired diagnostic is real or a false positive.

Fires on a non-static instance MethodDefinition named render (kind 'method', static !== true) whose owning class extends Component or PureComponent — imported from preact, or referenced as the Preact namespace member Preact.Component / Preact.PureComponent, or the React.Component shape that isEs6Component recognizes (e.g. preact/compat) — when that render's FunctionExpression declares at least one runtime parameter (props, or props plus state). A leading TypeScript this: type-only parameter is stripped first, so it does not count. False positive boundary mirroring the valid fixtures: parameterless render() reading this.props/this.state; a render(target) on a plain class that does NOT extend a Component/PureComponent base; a function component or arrow assigned const render = (props) => ...; a static render(input) utility sharing the name; and render(this: Hello) where the only param is the type-only this binding with an otherwise empty runtime arg list.

Fix prompt

Use this once validation confirms the diagnostic is real.

Remove the positional parameter(s) from the lifecycle render() and read the same values off the instance instead: change render(props, state) { return <h1>{props.name} {state.count}</h1>; } to render() { return <h1>{this.props.name} {this.state.count}</h1>; }. This types cleanly via Component<Props, State>, keeps render() consistent with every other lifecycle method, and survives a switch to preact/compat where render() takes no arguments. Leave a genuine this: type annotation in place but delete the user-declared props/state params after it. See https://preactjs.com/guide/v10/components/

More Bugs rules from the rules reference:

  • react-doctor/preact-prefer-ondblclick: Rename onDoubleClick to onDblClick on host elements: <li onDblClick={openInline}> — Preact uses DOM event names
  • react-doctor/preact-prefer-oninput: Replace onChange with onInput on text-like inputs: onInput={(e) => setQuery(e.currentTarget.value)}
  • react-doctor/prefer-use-effect-event: Wrap the callback with `useEffectEvent(callback)` (React 19+) and call the resulting binding from inside the sub-handler. The Effect Event captures the latest props/state without being a reactive dep, so the effect doesn't re-subscribe on every parent render. See https://react.dev/reference/react/useEffectEvent
  • react-doctor/prefer-use-sync-external-store: Replace the `useState(getSnapshot())` + `useEffect(() => store.subscribe(() => setSnapshot(getSnapshot())))` pair with `useSyncExternalStore(store.subscribe, getSnapshot)`. The hook handles tearing during concurrent renders and SSR snapshots; the manual subscribe pattern doesn't
  • react-doctor/prefer-useReducer: Group related state: `const [state, dispatch] = useReducer(reducer, { field1, field2, ... })`