All skills
softaworks avatar

/react-useeffect

@1c0662a
by softaworkssoftaworks/agent-toolkit2.5k stars
230

React useEffect best practices from official docs. Use when writing/reviewing useEffect, useState for derived values, data fetching, or state synchronization. Teaches when NOT to use Effect and better alternatives.

Use this Skill: https://skilld.dev/gh/softaworks/agent-toolkit/react-useeffect

This session only. Nothing lands on disk.

anti-patterns.md

≈1.5k tokens on demand. Your agent reads this file only when SKILL.md points to it.

useEffect Anti-Patterns

1. Redundant State for Derived Values

// BAD: Extra state + Effect for derived value
function Form() {
  const [firstName, setFirstName] = useState('Taylor');
  const [lastName, setLastName] = useState('Swift');
  const [fullName, setFullName] = useState('');

  useEffect(() => {
    setFullName(firstName + ' ' + lastName);
  }, [firstName, lastName]);
}

// GOOD: Calculate during rendering
function Form() {
  const [firstName, setFirstName] = useState('Taylor');
  const [lastName, setLastName] = useState('Swift');
  const fullName = firstName + ' ' + lastName; // Just compute it
}

Why it's bad: Causes extra render pass with stale value, then re-renders with updated value.


2. Filtering/Transforming Data in Effect

// BAD: Effect to filter list
function TodoList({ todos, filter }) {
  const [visibleTodos, setVisibleTodos] = useState([]);

  useEffect(() => {
    setVisibleTodos(getFilteredTodos(todos, filter));
  }, [todos, filter]);
}

// GOOD: Filter during render (memoize if expensive)
function TodoList({ todos, filter }) {
  const visibleTodos = useMemo(
    () => getFilteredTodos(todos, filter),
    [todos, filter]
  );
}

3. Resetting State on Prop Change

// BAD: Effect to reset state
function ProfilePage({ userId }) {
  const [comment, setComment] = useState('');

  useEffect(() => {
    setComment('');
  }, [userId]);
}

// GOOD: Use key prop
function ProfilePage({ userId }) {
  return <Profile userId={userId} key={userId} />;
}

function Profile({ userId }) {
  const [comment, setComment] = useState(''); // Resets automatically
}

Why key works: React treats components with different keys as different components, recreating state.


4. Event-Specific Logic in Effect

// BAD: Effect for button click result
function ProductPage({ product, addToCart }) {
  useEffect(() => {
    if (product.isInCart) {
      showNotification(`Added ${product.name}!`);
    }
  }, [product]);

  function handleBuyClick() {
    addToCart(product);
  }
}

// GOOD: Handle in event handler
function ProductPage({ product, addToCart }) {
  function handleBuyClick() {
    addToCart(product);
    showNotification(`Added ${product.name}!`);
  }
}

Why it's bad: Effect fires on page refresh (isInCart is true), showing notification unexpectedly.


5. Chains of Effects

// BAD: Effects triggering each other
function Game() {
  const [card, setCard] = useState(null);
  const [goldCardCount, setGoldCardCount] = useState(0);
  const [round, setRound] = useState(1);
  const [isGameOver, setIsGameOver] = useState(false);

  useEffect(() => {
    if (card?.gold) setGoldCardCount(c => c + 1);
  }, [card]);

  useEffect(() => {
    if (goldCardCount > 3) {
      setRound(r => r + 1);
      setGoldCardCount(0);
    }
  }, [goldCardCount]);

  useEffect(() => {
    if (round > 5) setIsGameOver(true);
  }, [round]);
}

// GOOD: Calculate in event handler
function Game() {
  const [card, setCard] = useState(null);
  const [goldCardCount, setGoldCardCount] = useState(0);
  const [round, setRound] = useState(1);
  const isGameOver = round > 5; // Derived!

  function handlePlaceCard(nextCard) {
    if (isGameOver) throw Error('Game ended');

    setCard(nextCard);
    if (nextCard.gold) {
      if (goldCardCount < 3) {
        setGoldCardCount(goldCardCount + 1);
      } else {
        setGoldCardCount(0);
        setRound(round + 1);
        if (round === 5) alert('Good game!');
      }
    }
  }
}

Why it's bad: Multiple re-renders (setCard -> setGoldCardCount -> setRound -> setIsGameOver). Also fragile for features like history replay.


6. Notifying Parent via Effect

// BAD: Effect to notify parent
function Toggle({ onChange }) {
  const [isOn, setIsOn] = useState(false);

  useEffect(() => {
    onChange(isOn);
  }, [isOn, onChange]);

  function handleClick() {
    setIsOn(!isOn);
  }
}

// GOOD: Notify in same event
function Toggle({ onChange }) {
  const [isOn, setIsOn] = useState(false);

  function updateToggle(nextIsOn) {
    setIsOn(nextIsOn);
    onChange(nextIsOn); // Same event, batched render
  }

  function handleClick() {
    updateToggle(!isOn);
  }
}

// BEST: Fully controlled component
function Toggle({ isOn, onChange }) {
  function handleClick() {
    onChange(!isOn);
  }
}

7. Passing Data Up to Parent

// BAD: Child fetches, passes up via Effect
function Parent() {
  const [data, setData] = useState(null);
  return <Child onFetched={setData} />;
}

function Child({ onFetched }) {
  const data = useSomeAPI();

  useEffect(() => {
    if (data) onFetched(data);
  }, [onFetched, data]);
}

// GOOD: Parent fetches, passes down
function Parent() {
  const data = useSomeAPI();
  return <Child data={data} />;
}

Why: Data should flow down. Upward flow via Effects makes debugging hard.


8. Fetching Without Cleanup (Race Condition)

// BAD: No cleanup - race condition
function SearchResults({ query }) {
  const [results, setResults] = useState([]);

  useEffect(() => {
    fetchResults(query).then(json => {
      setResults(json); // "hello" response may arrive after "hell"
    });
  }, [query]);
}

// GOOD: Cleanup ignores stale responses
function SearchResults({ query }) {
  const [results, setResults] = useState([]);

  useEffect(() => {
    let ignore = false;

    fetchResults(query).then(json => {
      if (!ignore) setResults(json);
    });

    return () => { ignore = true; };
  }, [query]);
}

9. App Initialization in Effect

// BAD: Runs twice in dev, may break auth
function App() {
  useEffect(() => {
    loadDataFromLocalStorage();
    checkAuthToken(); // May invalidate token on second call!
  }, []);
}

// GOOD: Module-level guard
let didInit = false;

function App() {
  useEffect(() => {
    if (!didInit) {
      didInit = true;
      loadDataFromLocalStorage();
      checkAuthToken();
    }
  }, []);
}

// ALSO GOOD: Module-level execution
if (typeof window !== 'undefined') {
  checkAuthToken();
  loadDataFromLocalStorage();
}

Source: SKILL.md on GitHub

No alerts16d5 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    This skill provides educational guidance on React `useEffect` best practices and contains only descriptive markdown and code snippets without code execution capabilities.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer7mo

    4 files scanned · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 1c0662a. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Dormantupdated 8 months ago

README badge

README badge for softaworks/agent-toolkit/react-useeffect

Teaches when to use useEffect for external system synchronization and when to replace it with render-time calculations, useMemo, event handlers, or the key prop. Covers React's official best practices for useState and useEffect patterns, with a decision tree for choosing the right approach.

Generated from the current SKILL.md.

When should I use useEffect for data fetching?
Use useEffect for data fetching only when you include proper cleanup (e.g., abort controller) to avoid memory leaks. Better alternatives include framework-provided data fetching mechanisms like Next.js or Remix loaders.
Can I use useEffect to derive state from props?
No. Instead, calculate derived values during render at the top level of your component—they'll update automatically when props change. For expensive calculations, wrap with useMemo.
What's the difference between using useEffect with setState versus a key prop to reset state?
When a prop changes, use the key prop on the component to force React to remount it, which naturally resets state. Avoid useEffect with setState for this pattern.
Should I use useEffect to respond to user events like clicks?
No. Use event handlers directly—you know exactly what triggered the action. useEffect is for synchronizing with external systems, not responding to user interaction.

Generated from the current SKILL.md. These answers refresh after source changes.