react-useeffect-doctor
v0.1.0
Published
Find React useEffect calls that may be unnecessary.
Maintainers
Readme
React useEffect Doctor
A read-only CLI that finds React useEffect calls which may be unnecessary.
This tool uses heuristics. Findings are review candidates, not definite errors.
npx react-useeffect-doctor "src/**/*.{js,jsx,ts,tsx}"Requires Node.js 20 or newer.
Usage
react-useeffect-doctor [--config <path>] [path-or-glob ...]With no input, the CLI scans the current directory recursively. Quote globs for consistent cross-platform matching.
The scanner reads .js, .jsx, .ts, and .tsx files. It always excludes files inside node_modules and dist.
Rules
| Rule | Reports | Prefer |
| --- | --- | --- |
| derived-or-copied-state | An Effect that calls a state setter without recognized external-system work | Calculate during render; use useMemo only for expensive work |
| initial-state | An Effect with [] that only calls a state setter | Initialize with useState or at module scope |
| parent-notification | An Effect with dependencies that only calls a callback such as onChange | Call the callback from the event handler that changed the value |
Effects with recognized fetch, subscription, event, timer, browser, storage, observer, socket, worker, or broadcast work are excluded from these rules.
Configuration
The CLI automatically loads .react-useeffect-doctor.json from the current directory. Use --config <path> to select another file.
{
"exclude": {
"files": ["src/Legacy.tsx"],
"patterns": ["**/*.generated.{ts,tsx}"]
}
}exclude is required; files and patterns are optional. Entries are relative to the config file's directory, must stay inside that directory, and override explicit scan inputs. files are literal paths; patterns are globs.
Suppress an intentional Effect
Add effect-lint-ignore to a line or block comment inside that Effect:
useEffect(() => {
// effect-lint-ignore -- sync with a non-standard external system
setStatus(readExternalStatus())
}, [])The comment suppresses only its containing Effect.
Exit statuses
0: no findings. An unmatched glob is also a valid clean scan.1: one or more findings.2: usage, configuration, or scanning error. A missing literal input file is an error.
Limitations
The tool uses regular expressions and shallow delimiter matching, not a JavaScript or TypeScript syntax tree. Complex control flow, nested callbacks, aliased hooks, custom Effect wrappers, some TypeScript generics, regular-expression literals with structural delimiters, and other valid syntax can cause false positives or missed findings.
Review each warning before changing code. The CLI never modifies source files.
