
React Best Practices
Apply vetted React rendering, Effect, and state patterns so agents stop introducing derived-state bugs and unnecessary re-renders.
Overview
React Best Practices is an agent skill most often used in Build (also Ship review) that supplies concrete React pattern examples to avoid Effect misuse and unstable derived state.
Install
npx skills add https://github.com/0xbigboss/claude-code --skill react-best-practicesWhat is this skill?
- Effect anti-patterns: derive state during render instead of syncing with useEffect
- useMemo for expensive filtered or computed lists tied to todos/filter-style deps
- Reset child state on prop changes with key={userId} instead of effect clears
- Concrete BAD vs GOOD snippets agents can mirror in PRs
- Pairs with code review skills for React-specific smell detection
- Multiple named anti-pattern sections: derived state, expensive calculations, prop-change resets
Adoption & trust: 2.8k installs on skills.sh; 49 GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
Your agent keeps adding useEffect chains for values you could compute in render, causing extra renders and hard-to-debug state drift.
Who is it for?
Solo builders using React or Next.js who want copy-paste GOOD/BAD examples when pairing with an agent on feature work.
Skip if: Greenfield projects on non-React frameworks, or teams that already enforce a strict internal design system doc the skill would duplicate.
When should I use this skill?
When implementing or reviewing React components and the agent needs concrete BAD vs GOOD pattern examples from the reference.
What do I get? / Deliverables
After applying the skill, components use render-time derivation, targeted useMemo, and key-based resets so UI code is easier to ship and review.
- Refactored components following documented patterns
- Review comments mapped to specific anti-pattern fixes
Recommended Skills
Journey fit
Spans multiple journey phases - primary shelf plus alternate fits below.
React quality lands first in Build while you implement UI, but the same rules matter again in Ship review before merge. Frontend subphase is the canonical shelf because the reference encodes component-level patterns (useMemo, keys, effect avoidance) used daily in React code.
Where it fits
Agent drafts a profile form and you enforce key={userId} so comment state resets per user without an Effect.
You scan a PR for Effect-driven fullName sync and point the agent at the derive-during-render example.
You refactor a slow todo list filter from useEffect setState to useMemo before shipping a perf fix.
How it compares
Pattern reference for hooks discipline—not a component library generator or a visual design skill.
Common Questions / FAQ
Who is react-best-practices for?
Solo and indie developers writing React UIs with AI agents who need authoritative snippets for effects, memoization, and state reset patterns.
When should I use react-best-practices?
Use it in Build (frontend) while implementing components; in Ship (review) before merging agent-generated React; and in Operate (iterate) when refactoring legacy Effect-heavy code.
Is react-best-practices safe to install?
It is documentation-style patterns without mandated shell access; still review the Security Audits panel on this page before installing from the repo.
SKILL.md
READMESKILL.md - React Best Practices
# React Patterns Reference Code examples for patterns summarized in `SKILL.md`. Load this file when you need to see or produce a concrete implementation. ## Effect Anti-Patterns ### Derived State (Calculate During Render) ```tsx // BAD: Effect for derived state const [firstName, setFirstName] = useState('Taylor'); const [lastName, setLastName] = useState('Swift'); const [fullName, setFullName] = useState(''); useEffect(() => { setFullName(firstName + ' ' + lastName); }, [firstName, lastName]); // GOOD: Calculate during render const [firstName, setFirstName] = useState('Taylor'); const [lastName, setLastName] = useState('Swift'); const fullName = firstName + ' ' + lastName; ``` ### Expensive Calculations (Use useMemo) ```tsx // BAD: Effect for caching const [visibleTodos, setVisibleTodos] = useState([]); useEffect(() => { setVisibleTodos(getFilteredTodos(todos, filter)); }, [todos, filter]); // GOOD: useMemo for expensive calculations const visibleTodos = useMemo( () => getFilteredTodos(todos, filter), [todos, filter] ); ``` ### Resetting State on Prop Change (Use key) ```tsx // BAD: Effect to reset state function ProfilePage({ userId }) { const [comment, setComment] = useState(''); useEffect(() => { setComment(''); }, [userId]); } // GOOD: Use key to reset component state function ProfilePage({ userId }) { return <Profile userId={userId} key={userId} />; } function Profile({ userId }) { const [comment, setComment] = useState(''); // Resets automatically when key changes } ``` ### User Event Handling (Use Event Handlers) ```tsx // BAD: Event-specific logic in Effect function ProductPage({ product, addToCart }) { useEffect(() => { if (product.isInCart) { showNotification(`Added ${product.name} to cart`); } }, [product]); } // GOOD: Logic in event handler function ProductPage({ product, addToCart }) { function buyProduct() { addToCart(product); showNotification(`Added ${product.name} to cart`); } } ``` ### Notifying Parent of State Changes ```tsx // BAD: Effect to notify parent function Toggle({ onChange }) { const [isOn, setIsOn] = useState(false); useEffect(() => { onChange(isOn); }, [isOn, onChange]); } // GOOD: Update both in event handler function Toggle({ onChange }) { const [isOn, setIsOn] = useState(false); function updateToggle(nextIsOn) { setIsOn(nextIsOn); onChange(nextIsOn); } } // BEST: Fully controlled component function Toggle({ isOn, onChange }) { function handleClick() { onChange(!isOn); } } ``` ### Chains of Effects ```tsx // BAD: Effect chain — each effect re-renders before the next fires useEffect(() => { if (card !== null && card.gold) { setGoldCardCount(c => c + 1); } }, [card]); useEffect(() => { if (goldCardCount > 3) { setRound(r => r + 1); setGoldCardCount(0); } }, [goldCardCount]); // GOOD: Calculate derived state, update everything in one event 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); } } } ``` ## Effect Dependencies ### Never Suppress the Linter ```tsx // BAD: Suppressing linter hides bugs useEffect(() => { const id = setInterval(() => { setCount(count + increment); }, 1000); return () => clearInterval(id); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // GOOD: Fix the code, not the linter useEffect(() => { const id = setInterval(() => { setCount(c => c + increment); }, 1000); return () => clearInterval(id); }, [increment]); ``` ### Use Updater Functions to Remove State Dependencies ```tsx // BAD: messages in dependencies causes reconnection on every message useEffect(() => { connection.on('message', (msg) => { setMessages([...messages, msg]); }); }, [messages]); // Reconnects on every message! // GOOD: