react-doctor/no-derived-useState
Remove useState and compute the value inline: `const value = transform(propName)`
- Category: State & Effects
- Severity: warn
- Source:
oxlint-plugin-react-doctor - Framework: global
- Enabled when: always
Validation prompt
Use this to decide whether a fired diagnostic is real or a false positive.
Fires on useState(propName) or useState(propName.nested) where propName is a destructured prop or props.x reference tracked by the per-component prop-stack. Only direct Identifier and non-computed MemberExpression initializers are checked — useState(transform(prop)) or useState(() => transform(prop)) will not trigger. False positive: an intentionally uncontrolled-component pattern that captures the initial prop value ONCE and never re-syncs.
Fix prompt
Use this once validation confirms the diagnostic is real.
Delete the useState and read the prop directly during render: const value = transform(propName). If you need a separate editable local copy that resets when the prop changes, lift the prop to a key on the component — <Form key={userId} initialValue={...} /> — so React remounts with a fresh useState on each change. See https://react.dev/learn/you-might-not-need-an-effect#resetting-all-state-when-a-prop-changes
Related rules
More State & Effects rules from the rules reference:
react-doctor/no-did-mount-set-state: Derive state in getDerivedStateFromProps or initial state instead of calling this.setState in componentDidMount, which forces an extra render.react-doctor/no-did-update-set-state: Avoid calling this.setState in componentDidUpdate; derive the value with getDerivedStateFromProps to prevent re-render loopsreact-doctor/no-direct-state-mutation: Replace the mutation with a setter call that produces a new reference: `setItems([...items, newItem])`, `setItems(items.filter(x => x !== target))`, `setItems(items.toSorted(...))`. React only re-renders on a new reference, so in-place updates are silently droppedreact-doctor/no-effect-chain: Compute as much as possible during render (e.g. `const isGameOver = round > 5`) and write all related state inside the event handler that originally fires the chain. Each effect link adds an extra render and makes the code rigid as requirements evolvereact-doctor/no-effect-event-handler: Move the conditional logic into onClick, onChange, or onSubmit handlers directly