About react-ban-use-effect
A React development skill for reviewing and replacing direct `useEffect` calls with alternatives suited to the behavior. It guides scoped migrations, legitimate external-system hooks, and lint and test verification.
Key features
- 01Classify direct effects and wrappers
- 02Prefer render, data, event, or keyed alternatives
- 03Define narrow external-system hooks
- 04Set scoped lint enforcement
- 05Verify changes with project gates
Use cases
- 01Review React code for unnecessary effects
- 02Migrate effects in a touched code area
- 03Document an external synchronization boundary
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ uinaf/ agent-skills --skill react-ban-use-effectAfter installing, type/react-ban-use-effectin Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
evals/mechanical-effect-guardrail/criteria.jsontask.mdevals/vendor-map-widget/criteria.jsontask.mdreferences/replacements.mdupstream.mdDetails
From the project READMEReact Ban useEffect
Direct useEffect is an external-synchronization escape hatch. Components do
not call it; a reviewed, domain-specific hook for a real external system may.
Scope
Effect replacement changes the touched behavior. Repository-wide lint enforcement is a separate task: apply it when requested or required by existing repository policy. A review request produces findings; an implementation request authorizes in-scope replacements and verification without another approval checkpoint.
Workflow
-
Find direct imports,
React.useEffect(...)namespace calls, and wrappers arounduseEffectin the touched surface. -
Classify each effect and replace it in this order of preference:
- render-time calculation
- server, loader, or framework data API
- the repository's server-state layer (for example a TanStack Query
queryOptionsfactory with variables in the key and thesignalpassed through) - event handler, action, or mutation
- keyed component boundary
useSyncExternalStore- reviewed domain-specific hook for a real external system
If none fits, state the external synchronization contract before keeping an effect. Replacements covers the non-obvious cases.
-
Preserve the repository's framework, data layer, lint shape, and dependency policy. Add a library only when the request or repository policy authorizes it; without a server-state layer, call the remaining effect a design gap.
-
Run lint, type, and test gates plus the smallest real UI or hook check for the changed behavior.
Legitimate Effects
Put every legitimate effect in a hook named for its external system (a chat connection, a map SDK, a widget), in its own file. The hook owns setup and cleanup, takes its reactive inputs as parameters, and lists every value setup or cleanup reads. The component calling it stays effect-free. Prefer an existing repository hook.
Never:
- write a generic wrapper that takes a callback and a caller-provided
dependency array (
useUpdateEffect(fn, deps),useAsyncEffect(fn, deps),useMountEffect(fn)); - suppress
react-hooks/exhaustive-deps; - use an exception hook to fetch server state, copy props into state, relay user actions, or hide a reset that belongs at a keyed boundary.
Enforcement
When enforcement is in scope, extend the repository's existing linter so it
rejects both named useEffect imports and React.useEffect(...) calls. Allow
only the named, reviewed integration-hook files, never a directory such as
src/hooks/**, and never a generic wrapper; report the wrapper and its callers
as violations to migrate. Keep the canonical local gate and CI on that same lint
surface; agent guidance or optional scanners do not replace it. Do not use
@latest diagnostic tools as durable enforcement.
In review, every new direct effect is a finding unless the change documents and proves a legitimate external-system boundary. Ask for a replacement, not dependency-array tuning.
Boundaries
- Scope migrations to the touched or requested surface.
- Leave
useLayoutEffect,useInsertionEffect, framework lifecycle APIs, and non-React effect systems alone, including in lint rules, unless requested. - Apply performance primitives only for measured behavior or an established repository pattern.
- Upstream attribution: upstream.