React Component Reviewer
Deep review of React/TSX components against a 12-point checklist: hook violations, missing keys, ARIA attributes, memoization, prop drilling, missing dependencies, and more.
@atapifire/react-component-reviewer
React Component Reviewer
Purpose: Perform a deep, systematic review of a React TypeScript component (.tsx) against a specific 12-point checklist. Goes beyond generic code review to catch React-specific anti-patterns that general reviewers miss. Produces annotated findings with exact fix suggestions.
Invocation
/react-review <file.tsx>
The 12-Point Checklist
1. Hook Order Violations
- Are hooks called conditionally or inside loops? (breaks Rules of Hooks)
- Are hooks called in the same order on every render?
2. Missing key Props in Lists
- Every
.map()that returns JSX must have a stablekeyprop keymust not be the array index when the list can reorder or filter
3. Missing or Incorrect ARIA Attributes
- Interactive elements (
<div onClick>,<span onClick>) must haveroleand keyboard handlers - Images must have
altattribute (empty stringalt=""for decorative images) - Form inputs must have associated
<label>viahtmlFororaria-label - Modal/dialog elements must have
aria-modal,role="dialog", and focus trap
4. Missing React.memo on Pure Components
- Components that receive complex objects as props and re-render frequently
- Components that are used inside lists and receive non-primitive props
- Note:
memois not needed everywhere — flag only genuine candidates
5. Prop Drilling Deeper Than 2 Levels
- Props passed through 3+ component layers without being used in intermediate components
- Suggest: React Context, component composition, or lifting state differently
6. useEffect Missing Dependencies or Stale Closures
- Variables used inside
useEffectbut not in the dependency array - Functions defined outside
useEffectused inside without being in deps - Missing
useCallbackon functions passed as deps
7. Unhandled Loading and Error States
- Data-fetching components must render loading state (skeleton, spinner, or message)
- Data-fetching components must render error state with actionable message
- Empty state when data is
[]ornullshould be handled
8. Hardcoded Strings That Should Be Constants
- URLs, error messages, magic numbers used directly in JSX
- Strings used in multiple places without being defined as constants
9. any Type Usage
- Every
anyannotation in the component is a type safety hole - Suggest
unknownwith type narrowing, or proper interface definition
10. Missing Null Checks on Optional Props
- Optional chaining (
?.) used but result not checked before rendering - Props that could be
undefinedrendered without a fallback
11. Direct DOM Mutation
document.getElementById()ordocument.querySelector()inside a component- Suggest
useRef()for DOM access
12. Missing Suspense Boundary for Async Components
- Components using
use(),React.lazy(), or async Server Components - Must be wrapped in
<Suspense fallback={...}>at the appropriate level
Output Format
For each finding:
[SEVERITY] Checklist Item #N — file.tsx:line
Issue: [what's wrong]
Fix: [exact code change or pattern to use]
Severity:
CRITICAL— Will cause runtime errors or accessibility failuresHIGH— Causes incorrect behavior or major UX issuesMEDIUM— Performance or maintainability concernLOW— Style or minor improvement
End with:
## Component Review Summary
Checklist items reviewed: 12/12
Issues found: [N] (Critical: N, High: N, Medium: N, Low: N)
Verdict: APPROVE / REQUEST CHANGES / NEEDS MAJOR REWORK
Rules
- All 12 checklist items must be evaluated — "No issues" is a valid finding for each
- Don't flag
React.memoabsence unless there's genuine evidence of unnecessary re-renders key={index}in a static, non-reorderable list is acceptable — flag only if the list can change- ARIA issues are always
HIGHorCRITICAL— accessibility is not optional
Playground
<!DOCTYPE html><html><head><meta charset='utf-8'><style>*{box-sizing:border-box;margin:0;padding:0}body{background:#0d1117;color:#e6edf3;font-family:monospace;font-size:12px;height:100vh;display:flex;flex-direction:column;overflow:hidden}.header{background:#161b22;border-bottom:1px solid #30363d;padding:8px 14px;font-size:11px;color:#8b949e;display:flex;justify-content:space-between;align-items:center;flex-shrink:0}.title{color:#58a6ff;font-weight:bold;font-size:13px}.panels{display:flex;flex:1;overflow:hidden}.panel{flex:1;overflow:auto;padding:12px;border-right:1px solid #30363d}.panel:last-child{border-right:none}.label{font-size:10px;color:#8b949e;text-transform:uppercase;letter-spacing:.08em;margin-bottom:6px}pre{white-space:pre-wrap;word-break:break-word;line-height:1.5}</style></head><body><div class='header'><span class='title'>React Component Reviewer</span><span>Example · SkillSlap</span></div><div class='panels'><div class='panel'><div class='label'>Input: React component</div><pre><span style='color:#8b949e'>function UserList() {</span><span style='color:#8b949e'> const [users, setUsers] = useState([])</span>
<span style='color:#8b949e'> useEffect(() => {</span>
<span style='color:#8b949e'> fetch('/api/users')</span>
<span style='color:#8b949e'> .then(r => r.json())</span>
<span style='color:#8b949e'> .then(setUsers)</span>
<span style='color:#8b949e'> }, [users])</span>
<span style='color:#8b949e'> return users.map(u =></span>
<span style='color:#8b949e'> <div>{u.name}</div></span>
<span style='color:#8b949e'> )</span>
<span style='color:#8b949e'>}</span></pre></div><div class='panel'><div class='label'>Output: Review</div><pre><span style='color:#f85149'>🔴 Infinite loop (line 5)</span>
<span style='color:#8b949e'>users in dep array triggers effect</span>
<span style='color:#8b949e'>on every state update → infinite fetch.</span>
<span style='color:#8b949e'>Fix: dep array should be []</span>
<span style='color:#f85149'>🔴 Missing key prop (line 8)</span> <span style='color:#8b949e'>React requires unique key on list items.</span> <span style='color:#8b949e'>Fix: <div key={u.id}></span>
<span style='color:#e3b341'>🟡 No loading/error state</span> <span style='color:#8b949e'>Blank screen while fetching, silent</span> <span style='color:#8b949e'>fail on error. Add isLoading + error.</span>
<span style='color:#e3b341'>🟡 No AbortController</span> <span style='color:#8b949e'>Fetch leaks if component unmounts.</span></pre></div></div></body></html>
$20 more to next tier
Created by
Info
Embed
Add this skill card to any webpage.
<iframe src="https://skillslap.com/skill/f7dcf5ca-d694-4ea1-8ee1-0e3786e3a90f/embed"
width="400" height="200"
style="border:none;border-radius:12px;"
title="SkillSlap Skill: React Component Reviewer">
</iframe>