coder

react-effects

@coder/react-effects
coder
864
43 forks
Updated 1/18/2026
View on GitHub

Guidelines for when to use (and avoid) useEffect in React components

Installation

$skills install @coder/react-effects
Claude Code
Cursor
Copilot
Codex
Antigravity

Details

Repositorycoder/mux
Path.mux/skills/react-effects/SKILL.md
Branchmain
Scoped Name@coder/react-effects

Usage

After installing, this skill will be available to your AI coding assistant.

Verify installation:

skills list

Skill Instructions


name: react-effects description: Guidelines for when to use (and avoid) useEffect in React components

React Effects Guidelines

Primary reference: https://react.dev/learn/you-might-not-need-an-effect

Quick Decision Tree

Before adding useEffect, ask:

  1. Can I calculate this during render? → Derive it, don't store + sync
  2. Is this resetting state when a prop changes? → Use key prop instead
  3. Is this triggered by a user event? → Put it in the event handler
  4. 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();
}