skills/react-effect-patterns/SKILL.md
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.
npx skillsauth add nbbaier/agent-skills react-effect-patternsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
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.
Why does this code run?
// ❌ Bad
const [fullName, setFullName] = useState("");
useEffect(() => {
setFullName(firstName + " " + lastName);
}, [firstName, lastName]);
// ✅ Good - calculate during render
const fullName = firstName + " " + lastName;
// ❌ 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.
// ❌ Bad
useEffect(() => {
setComment("");
}, [userId]);
// ✅ Good - use key to reset
<Profile userId={userId} key={userId} />;
// ❌ Bad
useEffect(() => {
setSelection(null);
}, [items]);
// ✅ Good - derive from state
const selection = items.find((item) => item.id === selectedId) ?? null;
// ❌ Bad
useEffect(() => {
if (product.isInCart) {
showNotification("Added " + product.name + "!");
}
}, [product]);
// ✅ Good - in event handler
function handleBuyClick() {
addToCart(product);
showNotification("Added " + product.name + "!");
}
// ❌ Bad
useEffect(() => {
if (jsonToSubmit !== null) {
post("/api/register", jsonToSubmit);
}
}, [jsonToSubmit]);
// ✅ Good - in event handler
function handleSubmit(e) {
e.preventDefault();
post("/api/register", { firstName, lastName });
}
// ❌ 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);
}
}
}
// ❌ 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();
}
}, []);
}
// ❌ 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);
}
}
// ❌ 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} />;
}
// ❌ 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,
);
// ✅ Correct - cleanup ignores stale responses
useEffect(() => {
let ignore = false;
fetchResults(query).then((json) => {
if (!ignore) setResults(json);
});
return () => {
ignore = true;
};
}, [query]);
| Scenario | Solution |
| ----------------------- | ------------------------------------ |
| Transform data | Calculate during render |
| Expensive calculation | useMemo |
| Reset all state on prop | key attribute |
| Adjust state on prop | Derive during render |
| Share event logic | Extract function, call from handlers |
| User events | Event handlers |
| External system sync | Effect |
| Notify parent | Update in handler or lift state |
| Init once | Module-level or guard variable |
| External store | useSyncExternalStore |
| Fetch data | Effect with cleanup |
development
Ideate and critique data visualizations using Edward Tufte's principles from "The Visual Display of Quantitative Information." Use this skill when: (1) Designing new data visualizations or charts (2) Critiquing or improving existing visualizations (3) Reviewing dashboards or reports for graphical integrity (4) Deciding between visualization approaches (5) Reducing chartjunk or improving data-ink ratio (6) Planning small multiples or high-density displays Applies principles: data-ink ratio, chartjunk elimination, graphical integrity, lie factor, small multiples, and data density.
tools
Manage Val Town projects using the vt CLI. Use when working with Vals (Val Town serverless functions), syncing code to Val Town, creating HTTP endpoints, streaming logs, or managing Val Town branches. Triggers on tasks involving Val Town development, val creation/editing, or when user mentions "vt", "val town", or "vals".
testing
Audit and harden Node.js projects against npm supply chain attacks — compromised maintainer accounts, malicious package versions, and install-script payloads. Use when reviewing or setting up package.json, lockfiles, .npmrc, Dockerfile, or CI workflows for security; when the user mentions npm security, supply chain attacks, `npm audit`, lockfile policy, install scripts, or min-release-age; also when the user wants to check whether their dependencies are safe, or recover from a suspected compromise.
tools
Use before implementing logs in a medium to large scale production system.