react-hooks-review
Skill7 starsChanged 4 months agoMITView on GitHub
Review React (functional component + hooks) code before you PR for common regressions. `useEffect` dependency-array bugs, stale closures in event handlers, `useState` set-with-stale-value, over-memoization, list `key` anti-patterns, async effect cleanup leaks, and Rules-of-Hooks violations that a lint pass missed. Triggers include "review this React code", "check my hooks", "why does my effect run twice", "am I using useMemo right".
In this repository14 other files it gives its agents.
- ai-tell-cleanupSkill
- branch-guardSkill
- frontend-perf-impact-scanSkill
- jvm-memory-leak-reviewSkill
- kotlin-coroutine-reviewSkill
- nestjs-provider-reviewSkill
- nextjs-app-router-reviewSkill
- parallel-devSkill
- parallel-dispatchSkill
- parallel-prSkill
- pr-impact-scanSkill
- review-loopSkill
- reviewSkill
- spring-kafka-listener-reviewSkill
The file
We split this skill into the rules it gives an agent
9 rules. About 0 are common, 5 are distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈5
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 17
Every value the effect body reads that is defined in component scope must appear in the deps.
- Very specific: line 18
Do not disable react-hooks/exhaustive-deps to "make the warning go away".
- Distinctive: line 30
Only useful when either (a) the memoized value is expensive to recompute, or (b) the value is passed to a memoized child or used as an …
- Very specific: line 31
Do not blanket-wrap every helper function in useCallback.
- Very specific: line 34
Never use array index as key for lists that can reorder, delete, or insert.
- Distinctive: line 35
Use a stable ID from the data.
- Very specific: line 39
Prefer AbortController and check signal.aborted before setState, or a mounted-flag ref pattern.
- Distinctive: line 42
No hooks inside conditionals, loops, or early returns.
- Distinctive: line 43
No hooks in event handlers or class components.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
react-hooks-review
Catches React regressions that ship green through TypeScript and eslint-plugin-react-hooks yet still cause production bugs. Runs before you open a PR.
What to check
1. useEffect dependency arrays
- Every value the effect body reads that is defined in component scope must appear in the deps. Missing deps mean stale reads.
- Do not disable
react-hooks/exhaustive-depsto "make the warning go away". If the warning is wrong, that is usually a signal to lift the value out or use a ref. - Deps that are recreated every render (inline objects, arrays, functions) reset the effect every render. Wrap in
useMemo/useCallbackor move outside the component.
2. Stale closures in event handlers
- A handler passed to a child at mount captures the values from that render. Later
setXcalls re-render, but the child still holds the old handler unless its props changed. - Fix by using
useCallbackwith proper deps, or by using the functional updater form ofuseState.
3. useState functional updater
setCount(count + 1)in an async callback can lose updates. PrefersetCount(c => c + 1).- Same for arrays:
setItems(items => [...items, x]), notsetItems([...items, x]).
4. useMemo and useCallback: perf theater vs actual need
- Only useful when either (a) the memoized value is expensive to recompute, or (b) the value is passed to a memoized child or used as an effect dep. Otherwise it costs memory plus a shallow compare per render.
- Do not blanket-wrap every helper function in
useCallback. That is noise.
5. List key prop
- Never use array index as
keyfor lists that can reorder, delete, or insert. React reuses component state across the wrong items. - Use a stable ID from the data. If none exists, add one on ingest, not on render.
6. Async effects: cleanup and cancellation
- Any effect that starts an async request must cancel it in the cleanup. Otherwise a race can
setStateafter unmount. - Prefer
AbortControllerand checksignal.abortedbeforesetState, or a mounted-flag ref pattern.
7. Rules of Hooks (silent violations)
- No hooks inside conditionals, loops, or early returns. Lint catches most cases. Watch for hooks called inside custom hooks that are themselves called conditionally.
- No hooks in event handlers or class components.
8. Server component leak (React 19 / Next App Router)
- Hooks in a component that ends up being a server component is a build error. Confirm the
"use client"boundary and where the component is imported from.
Common failure patterns to grep for
useEffect(() => { fetch(...) })with no cleanup and no deps.key={index}in a.map()that renders form inputs or components with internal state.setState(state + 1)insidesetTimeout,Promise.then, orWebSocket.onmessage.// eslint-disable-next-line react-hooks/exhaustive-depswithout a comment explaining why.
When to invoke
Trigger when the user asks for a React review, mentions hook confusion, or opens a PR touching *.tsx / *.jsx files with hook calls.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

