Best practices and decision framework for using useEffect in React.
Install
mkdir -p .claude/skills/react-effects && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/7131" && unzip -o skill.zip -d .claude/skills/react-effects && rm skill.zipInstalls to .claude/skills/react-effects
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Guidelines for when to use (and avoid) useEffect in React componentsKey capabilities
- →Identify state that can be derived during rendering
- →Replace state-resetting effects with key-prop re-mounting
- →Convert event-driven effects into direct event handlers
- →Migrate manual subscriptions to useSyncExternalStore
How it works
Applies a decision tree to evaluate if side effects are truly necessary, replacing them with declarative state management or event-based logic.
Inputs & outputs
When to use react-effects
- →Refactor code to replace unnecessary effects with derived state
- →Determine if an effect is needed for a specific data fetch
- →Identify better alternatives for state resetting on prop changes
- →Review component code for effect-related anti-patterns
About this skill
React Effects Guidelines
Primary reference: https://react.dev/learn/you-might-not-need-an-effect
Quick Decision Tree
Before adding useEffect, ask:
- Can I calculate this during render? → Derive it, don't store + sync
- Is this resetting state when a prop changes? → Use
keyprop instead - Is this triggered by a user event? → Put it in the event handler
- Am I syncing with an external system? → Effect is appropriate
Legitimate Effect Uses
- DOM manipulation (focus, scroll, measure)
- External widget lifecycle (terminal, charts, non-React libraries)
- Browser API subscriptions (ResizeObserver, IntersectionObserver)
- Data fetching on mount/prop change
- Global event listeners
Common Anti-Patterns
// ❌ Derived state stored separately
const [fullName, setFullName] = useState('');
useEffect(() => setFullName(first + ' ' + last), [first, last]);
// ✅ Calculate during render
const fullName = first + ' ' + last;
// ❌ Event logic in effect
useEffect(() => { if (isOpen) doSomething(); }, [isOpen]);
// ✅ In the handler
const handleOpen = () => { setIsOpen(true); doSomething(); };
// ❌ Reset state on prop change
useEffect(() => { setComment(''); }, [userId]);
// ✅ Use key to reset
<Profile userId={userId} key={userId} />
External Store Subscriptions
For subscribing to external data stores (not DOM APIs), prefer useSyncExternalStore:
// ❌ Manual subscription in effect
const [isOnline, setIsOnline] = useState(true);
useEffect(() => {
const update = () => setIsOnline(navigator.onLine);
window.addEventListener('online', update);
window.addEventListener('offline', update);
return () => { /* cleanup */ };
}, []);
// ✅ Built-in hook for external stores
const isOnline = useSyncExternalStore(
subscribe,
() => navigator.onLine, // client
() => true // server
);
Data Fetching Cleanup
Always handle race conditions with an ignore flag:
useEffect(() => {
let ignore = false;
fetchData(query).then(result => {
if (!ignore) setData(result);
});
return () => { ignore = true; };
}, [query]);
App Initialization
For once-per-app-load logic (not once-per-mount), use a module-level guard:
let didInit = false;
function App() {
useEffect(() => {
if (!didInit) {
didInit = true;
loadDataFromLocalStorage();
checkAuthToken();
}
}, []);
}
Or run during module initialization (before render):
if (typeof window !== 'undefined') {
checkAuthToken();
loadDataFromLocalStorage();
}
When not to use it
- →When handling actual DOM manipulations or browser API subscriptions
- →When connecting to non-React widget lifecycles
Limitations
- →Requires knowledge of React's render phase vs commit phase
- →Does not handle complex async orchestration without additional manual logic
How it compares
It actively promotes the removal of synchronization complexity, whereas generic prompts often suggest adding deps to fix errors.
Compared to similar skills
react-effects side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| react-effects (this skill) | 3 | 7mo | No flags | Intermediate |
| zustand | 113 | 2mo | No flags | Intermediate |
| accessibility-compliance | 45 | 2mo | No flags | Intermediate |
| react-modernization | 21 | 2mo | No flags | Advanced |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by coder
View all by coder →You might also like
zustand
lobehub
Zustand state management guide. Use when working with store code (src/store/**), implementing actions, managing state, or creating slices. Triggers on Zustand store development, state management questions, or action implementation.
accessibility-compliance
wshobson
Implement WCAG 2.2 compliant interfaces with mobile accessibility, inclusive design patterns, and assistive technology support. Use when auditing accessibility, implementing ARIA patterns, building for screen readers, or ensuring inclusive user experiences.
react-modernization
wshobson
Upgrade React applications to latest versions, migrate from class components to hooks, and adopt concurrent features. Use when modernizing React codebases, migrating to React Hooks, or upgrading to latest React versions.
react
lobehub
React component development guide. Use when working with React components (.tsx files), creating UI, using @lobehub/ui components, implementing routing, or building frontend features. Triggers on React component creation, modification, layout implementation, or navigation tasks.
frontend-testing
langgenius
Generate Vitest + React Testing Library tests for Dify frontend components, hooks, and utilities. Triggers on testing, spec files, coverage, Vitest, RTL, unit tests, integration tests, or write/review test requests.
feature-flags
Use when feature flag tests fail, flags need updating, understanding @gate pragmas, debugging channel-specific test failures, or adding new flags to React.