askill
react-effect-patterns

react-effect-patternsSafety 95Repository

Guidelines for proper React useEffect usage and avoiding unnecessary Effects. Use when writing, reviewing, or refactoring React components that use useEffect, useState, or handle side effects. Triggers on tasks involving React Effects, derived state, event handlers, data fetching, or component synchronization.

7 stars
1.2k downloads
Updated 2/8/2026

Package Files

Loading files...
SKILL.md

React Effect Patterns

Effects are an escape hatch from React for synchronizing with external systems. Removing unnecessary Effects makes code easier to follow, faster to run, and less error-prone.

When to Use Effects

  • Synchronizing with external systems (non-React widgets, network, browser DOM)
  • Analytics on component display
  • Data fetching (with cleanup for race conditions)

When NOT to Use Effects

  • Transforming data for rendering
  • Handling user events
  • Updating state based on other state

Decision Tree

Why does this code run?

  • Component displayed → Effect
  • User action → Event handler
  • Calculable from props/state → Calculate during render

Anti-Patterns and Solutions

1. Derived State

// ❌ Bad
const [fullName, setFullName] = useState("");
useEffect(() => {
   setFullName(firstName + " " + lastName);
}, [firstName, lastName]);

// ✅ Good - calculate during render
const fullName = firstName + " " + lastName;

2. Expensive Calculations

// ❌ Bad
const [visibleTodos, setVisibleTodos] = useState([]);
useEffect(() => {
   setVisibleTodos(getFilteredTodos(todos, filter));
}, [todos, filter]);

// ✅ Good - useMemo for expensive operations
const visibleTodos = useMemo(
   () => getFilteredTodos(todos, filter),
   [todos, filter],
);

Use console.time()/console.timeEnd() to measure. Memoize if ≥1ms.

3. Reset State on Prop Change

// ❌ Bad
useEffect(() => {
   setComment("");
}, [userId]);

// ✅ Good - use key to reset
<Profile userId={userId} key={userId} />;

4. Adjust Part of State on Prop Change

// ❌ Bad
useEffect(() => {
   setSelection(null);
}, [items]);

// ✅ Good - derive from state
const selection = items.find((item) => item.id === selectedId) ?? null;

5. Event-Specific Logic

// ❌ Bad
useEffect(() => {
   if (product.isInCart) {
      showNotification("Added " + product.name + "!");
   }
}, [product]);

// ✅ Good - in event handler
function handleBuyClick() {
   addToCart(product);
   showNotification("Added " + product.name + "!");
}

6. Form Submission

// ❌ Bad
useEffect(() => {
   if (jsonToSubmit !== null) {
      post("/api/register", jsonToSubmit);
   }
}, [jsonToSubmit]);

// ✅ Good - in event handler
function handleSubmit(e) {
   e.preventDefault();
   post("/api/register", { firstName, lastName });
}

7. Effect Chains

// ❌ Bad - cascading Effects
useEffect(() => {
   setGoldCardCount((c) => c + 1);
}, [card]);
useEffect(() => {
   setRound((r) => r + 1);
}, [goldCardCount]);
useEffect(() => {
   setIsGameOver(true);
}, [round]);

// ✅ Good - calculate + update in handler
const isGameOver = round > 5;

function handlePlaceCard(nextCard) {
   setCard(nextCard);
   if (nextCard.gold) {
      if (goldCardCount < 3) {
         setGoldCardCount(goldCardCount + 1);
      } else {
         setGoldCardCount(0);
         setRound(round + 1);
      }
   }
}

8. App Initialization

// ❌ Bad - runs twice in dev
useEffect(() => {
   loadDataFromLocalStorage();
   checkAuthToken();
}, []);

// ✅ Good - module level or guard
let didInit = false;
function App() {
   useEffect(() => {
      if (!didInit) {
         didInit = true;
         loadDataFromLocalStorage();
         checkAuthToken();
      }
   }, []);
}

9. Notify Parent of State Changes

// ❌ Bad - extra render pass
useEffect(() => {
   onChange(isOn);
}, [isOn, onChange]);

// ✅ Good - update both in handler
function updateToggle(nextIsOn) {
   setIsOn(nextIsOn);
   onChange(nextIsOn);
}

// ✅ Also good - lift state (controlled component)
function Toggle({ isOn, onChange }) {
   function handleClick() {
      onChange(!isOn);
   }
}

10. Pass Data to Parent

// ❌ Bad - child fetches, passes up
useEffect(() => {
   if (data) onFetched(data);
}, [data]);

// ✅ Good - parent fetches, passes down
function Parent() {
   const data = useSomeAPI();
   return <Child data={data} />;
}

11. External Store Subscription

// ❌ Bad - manual subscription
useEffect(() => {
   const handler = () => setIsOnline(navigator.onLine);
   window.addEventListener("online", handler);
   window.addEventListener("offline", handler);
   return () => {
      window.removeEventListener("online", handler);
      window.removeEventListener("offline", handler);
   };
}, []);

// ✅ Good - useSyncExternalStore
return useSyncExternalStore(
   subscribe,
   () => navigator.onLine,
   () => true,
);

12. Data Fetching with Race Conditions

// ✅ Correct - cleanup ignores stale responses
useEffect(() => {
   let ignore = false;
   fetchResults(query).then((json) => {
      if (!ignore) setResults(json);
   });
   return () => {
      ignore = true;
   };
}, [query]);

Quick Reference

ScenarioSolution
Transform dataCalculate during render
Expensive calculationuseMemo
Reset all state on propkey attribute
Adjust state on propDerive during render
Share event logicExtract function, call from handlers
User eventsEvent handlers
External system syncEffect
Notify parentUpdate in handler or lift state
Init onceModule-level or guard variable
External storeuseSyncExternalStore
Fetch dataEffect with cleanup

Install

Download ZIP
Requires askill CLI v1.0+

AI Quality Score

95/100Analyzed 2/11/2026

An exceptionally high-quality technical reference for React useEffect patterns, featuring clear anti-patterns, solutions, and a decision tree.

95
100
100
100
100

Metadata

Licenseunknown
Version-
Updated2/8/2026
PublisherNeverSight

Tags

api