Install for your agent
Download the file and place it at the path for your coding agent. Review the instructions before enabling a third-party skill.
Codex
~/.codex/skills/react-useeffect-cleanup-function/SKILL.mdClaude Code
.claude/skills/react-useeffect-cleanup-function/SKILL.mdCursor
.cursor/skills/react-useeffect-cleanup-function/SKILL.mdGitHub Copilot
.github/skills/react-useeffect-cleanup-function/SKILL.md</>View raw SKILL.mdInspect only the executable instructions your coding agent will receive, without catalog metadata.
---
name: "react-useeffect-cleanup-function"
description: "Implement and review React effects so events, timers, subscriptions, and requests are cleaned up correctly without stale dependencies or lifecycle leaks."
---
# Review useEffect Cleanup
Use this skill when implementing an effect, investigating a memory leak, reviewing dependencies, or fixing duplicate listeners, timers, subscriptions, or requests.
## Core rule
An effect synchronizes React with an external system. Its cleanup must undo the synchronization established by that execution. Cleanup runs before the effect executes again with changed dependencies and when the component unmounts.
## Workflow
1. Ask whether an effect is needed. Keep pure derivation and event-specific work outside effects.
2. List every external resource created by the effect.
3. Return cleanup that releases the exact same resource instance.
4. Include every reactive value read by the effect in its dependencies, or restructure the code so the dependency is no longer reactive.
5. Make setup and cleanup safe when development Strict Mode performs an extra setup-cleanup cycle.
6. Test mount, dependency change, unmount, rapid navigation, and failure paths.
## Cleanup patterns
For DOM events, remove the same event type, target, handler reference, and options used during setup.
For timers, store the returned id and call `clearInterval` or `clearTimeout`.
For sockets and observables, keep the subscription handle and unsubscribe or close it.
For requests, create an `AbortController` per effect execution, pass its signal, abort in cleanup, and treat an abort differently from a genuine failure.
```tsx
useEffect(() => {
const controller = new AbortController();
loadUser(userId, { signal: controller.signal });
return () => controller.abort();
}, [userId]);
```
## Common review findings
- Listener setup without removal.
- Cleanup using a new anonymous callback instead of the registered function.
- Timer ids lost across renders.
- Subscription cleanup omitted on dependency change.
- Stale values caused by an incomplete dependency list.
- An effect that copies props into state and creates unnecessary synchronization.
- Errors shown for intentionally aborted requests.
Do not disable the hooks linter as the first fix. Explain the resource lifecycle, update the smallest coherent area, and report how repeated setup and teardown were verified.
Use this skill when implementing an effect, investigating a memory leak, reviewing dependencies, or fixing duplicate listeners, timers, subscriptions, or requests.
Core rule
An effect synchronizes React with an external system. Its cleanup must undo the synchronization established by that execution. Cleanup runs before the effect executes again with changed dependencies and when the component unmounts.
Workflow
- Ask whether an effect is needed. Keep pure derivation and event-specific work outside effects.
- List every external resource created by the effect.
- Return cleanup that releases the exact same resource instance.
- Include every reactive value read by the effect in its dependencies, or restructure the code so the dependency is no longer reactive.
- Make setup and cleanup safe when development Strict Mode performs an extra setup-cleanup cycle.
- Test mount, dependency change, unmount, rapid navigation, and failure paths.
Cleanup patterns
For DOM events, remove the same event type, target, handler reference, and options used during setup.
For timers, store the returned id and call clearInterval or clearTimeout.
For sockets and observables, keep the subscription handle and unsubscribe or close it.
For requests, create an AbortController per effect execution, pass its signal, abort in cleanup, and treat an abort differently from a genuine failure.
useEffect(() => {
const controller = new AbortController();
loadUser(userId, { signal: controller.signal });
return () => controller.abort();
}, [userId]);
Common review findings
- Listener setup without removal.
- Cleanup using a new anonymous callback instead of the registered function.
- Timer ids lost across renders.
- Subscription cleanup omitted on dependency change.
- Stale values caused by an incomplete dependency list.
- An effect that copies props into state and creates unnecessary synchronization.
- Errors shown for intentionally aborted requests.
Do not disable the hooks linter as the first fix. Explain the resource lifecycle, update the smallest coherent area, and report how repeated setup and teardown were verified.