Awesome-claude-code useeffect-review

Reviews React code for correct useEffect usage. Use when reviewing React components, checking for useEffect anti-patterns, or deciding whether useEffect is appropriate for a given use case.

install
source · Clone the upstream repo
git clone https://github.com/houshuang/awesome-claude-code
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/houshuang/awesome-claude-code "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/useeffect-review" ~/.claude/skills/houshuang-awesome-claude-code-useeffect-review && rm -rf "$T"
manifest: skills/useeffect-review/SKILL.md
source content

useEffect Review

Reviews React code for correct useEffect usage based on official React documentation and team guidelines.

Core Principle

useEffect is for synchronizing with external systems, not for reacting to state changes. Before adding a useEffect, ask: "Am I connecting to something outside React?"

When useEffect is Appropriate

Use CaseExample
Event subscriptions
window.addEventListener
, WebSocket, event bus
External subscriptionsCRDT
onChange
handlers, real-time databases
Third-party librariesAnimation libraries, maps, charts
Timers and intervals
setTimeout
,
setInterval
DOM measurementsReading element dimensions after render

Common Anti-Patterns to Flag

Anti-PatternProblemSolution
Computing derived valuesExtra render cycleCalculate during render
Expensive calculationsExtra render cycleUse
useMemo
Resetting state on prop changeCascading re-rendersUse
key
prop
Adjusting state based on propsCascading re-rendersDerive during render
Responding to user eventsLoses event contextUse event handlers
Chaining state updatesMultiple render passesUpdate all state together
Notifying parent of changesExtra render cycleCall parent in event handler

Review Checklist

When reviewing useEffect usage, check:

  1. Is this synchronizing with an external system?

    • YES: useEffect is appropriate
    • NO: Don't use useEffect
  2. Does the effect call setState?

    • If so, this is probably wrong. The value should likely be:
      • Calculated during render
      • Computed with
        useMemo
      • Updated in an event handler
  3. Does the effect involve async operations?

    • Must have cleanup with cancelled flag or AbortController
  4. Does the effect set up subscriptions?

    • Must return a cleanup function

Required Patterns

Async Operations Must Have Cleanup

// Correct pattern
useEffect(() => {
  let cancelled = false;

  async function load() {
    const result = await fetchData(id);
    if (!cancelled) {
      setData(result);
    }
  }

  load();
  return () => {
    cancelled = true;
  };
}, [id]);

Fetch Must Use AbortController

useEffect(() => {
  const controller = new AbortController();

  fetch(url, { signal: controller.signal })
    .then((res) => res.json())
    .then(setData)
    .catch((err) => {
      if (err.name !== "AbortError") {
        setError(err);
      }
    });

  return () => controller.abort();
}, [url]);

Subscriptions Must Return Cleanup

useEffect(() => {
  const unsubscribe = eventBus.on("event", handler);
  return unsubscribe;
}, [handler]);

Decision Flowchart

Is this synchronizing with an external system?
|
+- YES -> useEffect is appropriate
|   +- Does it involve async operations?
|       +- YES -> Add cleanup (cancelled flag or AbortController)
|       +- NO -> Ensure cleanup for subscriptions
|
+- NO -> Don't use useEffect
    |
    +- Is it derived from props/state?
    |   +- Calculate during render
    |
    +- Is it an expensive calculation?
    |   +- Use useMemo
    |
    +- Is it responding to a user action?
    |   +- Handle in event handler
    |
    +- Does state need to reset when a prop changes?
    |   +- Use key prop on component
    |
    +- Are you chaining multiple state updates?
        +- Update all state in one event handler

References