react-hook-authoring-fix
React Hook Authoring Fix
Audits custom hooks using the react-hook-authoring skill principles and applies fixes.
Workflow
Step 1 — Resolve files
Parse the argument as file paths or glob patterns. If no argument is provided, ask:
"Which hook files should I audit? Pass file paths or glob patterns (e.g.
registry/hooks/*.ts)."
Step 2 — Load principles
Read ../react-hook-authoring/SKILL.md for the decision tree and antipatterns.
Read ../react-hook-authoring/references/approaches.md for Approach A/B details.
Step 3 — Audit each hook
For each file containing a custom hook (function starting with use and using React hooks internally):
- Read the file contents
- Check for each antipattern:
| # | Check | What to look for |
|---|---|---|
| 1 | Premature useCallback | useCallback where any dep is unstable (props callback, filtered array, new object) — the memoization achieves nothing |
| 2 | Side effect in state updater | onChange/callback invoked inside setState((prev) => { ... }) — fires 2x in Strict Mode |
| 3 | Ref-during-render | ref.current = value in component body without useLayoutEffect — tearing risk. OK only if no "use client" (SSR constraint) |
| 4 | Forcing consumer memoization | Callback from consumer in useEffect/useCallback deps — consumer must useCallback or hook misbehaves |
| 5 | Overengineered pattern | Multiple refs + useCallback + useLayoutEffect when plain function (Approach A) would suffice. Look for: no context consumers, no measured perf issue, hook used in <5 places |
| 6 | useMemo on primitives | useMemo returning string/number/boolean — pointless, compared by value |
| 7 | useCallback without memo on child | Function memoized but passed to non-memo() component |
| 8 | Unstable context value | Context Provider without useMemo on value object — all consumers re-render on every parent render |
| 9 | Missing Object.is check | onChange called without checking if value actually changed — unnecessary parent updates |
- For each issue, record:
- Line number(s)
- Check # (1-9)
- Severity: high (bug/DX problem), medium (unnecessary complexity), low (style)
- The offending code (1-5 lines)
- Suggested approach (A or B, or specific fix)
Step 4 — Classify fixes
-
Auto-fixable (mechanical, safe):
- Remove
useCallbackwith unstable deps → plain function (Check 1) - Remove
useMemoon primitives (Check 6) - Add
useMemoon context value object (Check 8)
- Remove
-
Semi-auto (likely safe, brief explanation before applying):
- Move
onChangeout of state updater (Check 2) - Replace ref-during-render with
useLayoutEffect(Check 3) - Simplify overengineered hook to Approach A (Check 5)
- Add
Object.isguard beforeonChange(Check 9)
- Move
-
Manual only (report, don't fix):
- Consumer memoization requirement (Check 4) — needs API change
- useCallback without memo (Check 7) — needs consumer-side change
- Switching from Approach B to A when context consumers exist — needs profiling
Step 5 — Apply fixes
Process fixes bottom-up within each file (highest line number first).
For auto-fixable: apply silently, record change. For semi-auto: state what changes and why, then apply. For manual: list in report only.
Step 6 — Output report
## Hook Authoring Audit Report
**Files audited:** N
**Issues found:** N (H high, M medium, L low)
---
### `path/to/hook.ts`
| Line | Severity | Check | Issue |
|------|----------|-------|-------|
| 23 | high | #2: Side effect in updater | `onChange?.(resolved)` inside `setInternal((prev) => ...)` |
| 40 | medium | #1: Premature useCallback | `useCallback([isControlled, onChange])` — onChange is unstable |
**Changes applied:**
- L23: Moved `onChange` call after `setInternal`
- L40: Replaced `useCallback` with plain function (Approach A)
**Manual review needed:**
- L67: Consumer must `useCallback` on `onFilter` prop or `useEffect` at L70 re-runs
---
### Summary
| Check | Count |
|-------|-------|
| 1. Premature useCallback | N |
| 2. Side effect in updater | N |
| ... | ... |
### Verify
Run type-check and tests to confirm nothing broke:
\`\`\`bash
pnpm type-check && pnpm test
\`\`\`
If zero issues found:
## Hook Authoring Audit Report
**Files audited:** N
**Issues found:** 0
Clean. No hook authoring issues detected.
More from b4r7x/agent-skills
react-design-patterns
Use when choosing a React component pattern — custom hooks, control props, compound components, headless components, render props, container/presentational, or other architectural patterns. Includes 13 patterns with decision guide and 2025 popularity ranking.
26human-commit
Generates human-like git commit messages based on staged or unstaged changes. Reads git diff, analyzes what changed, and outputs 3 natural commit message options that sound like they were written by a developer — not AI. This skill should be used when the user wants a commit message, asks "what should I write for commit", "generate commit message", "human like commit", "wiadomość do commita", or just asks for help committing.
24humanize-readme
Rewrites a README.md to remove AI slop — buzzwords, generic openers, fake enthusiasm, and formulaic structure — replacing it with direct, honest, human-sounding writing. This skill should be used when the user wants to humanize a README, remove AI-generated writing patterns, make documentation sound less like ChatGPT wrote it, or asks to "fix the README", "humanize readme", "remove AI slop", "make it sound human".
24improve-prompt
Transforms a rough, unpolished prompt idea into a precise, structured AI coding prompt. Automatically researches the current project context (stack, file structure, conventions, git history) before generating. This skill should be used when the user provides a vague or "dirty" prompt idea and asks to refine, improve, or rewrite it — e.g. "improve this prompt", "refine my prompt", "ulepszony prompt", "dopracuj prompt", or simply describes what they want done in rough terms.
23react-anti-patterns
Use when reviewing React code — especially AI-generated code — to catch common anti-patterns. Covers 18 anti-patterns with detection difficulty, including stale closures, state mutation, useEffect abuse, and boolean explosion.
21deep-plan
Takes a rough, unpolished prompt idea and autonomously turns it into an implementation plan. Researches the project deeply, asks clarifying questions, generates a precise internal prompt, then executes it to produce a structured plan with todos. Designed for plan mode. Use when the user gives a vague feature request, rough idea, or "dirty" prompt and wants a ready-to-execute implementation plan — e.g. "plan this", "deep plan", "turn this into a plan", "zaplanuj to", "zrób plan".
19