react-review
Comprehensive React/JSX code review for hook correctness, render performance, server/client component boundaries, accessibility, and React-specific security. Invokes the react-reviewer agent (and typescript-reviewer alongside on TSX/JSX changes).
React Code Review
This command invokes the react-reviewer agent for React-specific code review. For pull requests touching .tsx/.jsx files, both react-reviewer and typescript-reviewer should run — each owns a distinct lane.
What This Command Does
- Identify React Changes: Find modified
.tsx/.jsxfiles (and React-containing.ts/.jsfiles) viagit diff - Run Lint: Execute
eslintwitheslint-plugin-react-hooksandeslint-plugin-jsx-a11y - Typecheck: Run
tsc --noEmitor the project’s canonical typecheck command - Review React Lanes Only: Hook rules, RSC boundaries, accessibility, render performance, React-specific security
- Generate Report: Categorize issues by severity (CRITICAL / HIGH / MEDIUM)
When to Use
Use /react-review when:
- A PR or commit touches
.tsx/.jsxfiles - After writing or modifying React components, custom hooks, or pages
- Before merging React code
- Auditing accessibility on UI components
- Reviewing a new hook for rules-of-hooks and dependency correctness
- Auditing a Next.js App Router server/client component boundary
For pure .ts/.js changes with no React imports, use /code-review (general) or invoke typescript-reviewer directly.
Scope vs /code-review and TypeScript Review
| Tool | Scope |
|---|---|
react-reviewer (this command) | Hooks rules, JSX, RSC, a11y, React-specific security, render perf |
typescript-reviewer | Generic TS/JS — any abuse, async correctness, Node security |
security-reviewer | Project-wide security audit |
/code-review | Generic uncommitted-changes or PR review |
On a TSX/JSX PR, invoke both react-reviewer and typescript-reviewer. Findings from each are non-overlapping by design.
Review Categories
CRITICAL (Must Fix)
dangerouslySetInnerHTMLwith unsanitized inputhref/srcwith unvalidated user URLs (javascript:,data:)- Server Action without input validation
- Secret in client bundle (
NEXT_PUBLIC_*,VITE_*,REACT_APP_*) localStorage/sessionStoragefor session tokens- Conditional hook calls (violates Rules of Hooks)
- Direct state mutation
- Hook called outside a component or custom hook
HIGH (Should Fix)
- Missing
useEffect/useMemo/useCallbackdeps (disabledexhaustive-depswithout justification) - Effect for derived state
- Effect missing cleanup
- Stale closures in handlers/intervals
- Server-only imports in Client Components
- Sensitive data leaked via props to Client Components
- Server Actions without auth checks
- Accessibility violations (missing labels, non-semantic interactive elements, ARIA misuse)
key={index}in dynamic lists- Duplicated state, useEffect chains
MEDIUM (Consider)
- Over-memoization without measured win
- Inline new object/function as prop to memoized child
- Suspense at route root only (no progressive reveal)
- Long lists without virtualization
- High-frequency value via
useContext - Roll-your-own validation in non-trivial forms
- Prop drilling beyond 3 levels
- Component over 200 lines
- Class components in new code
Automated Checks Run
# Lint (required for any meaningful review)npx eslint . --ext .tsx,.jsx,.ts,.js
# Typecheck (skip cleanly for JS-only projects)npm run typecheck --if-present[ -f tsconfig.json ] && tsc --noEmit -p tsconfig.json
# Targeted a11y rulesnpx eslint . --rule 'jsx-a11y/alt-text: error' \ --rule 'jsx-a11y/anchor-is-valid: error' \ --rule 'jsx-a11y/click-events-have-key-events: error'
# Supply-chainnpm auditIf eslint-plugin-react-hooks or eslint-plugin-jsx-a11y is not configured, the review will flag the gap as a HIGH config issue and continue.
Example Usage
User: /react-review
Agent:# React Code Review Report
## Files Reviewed- src/components/UserCard.tsx (modified)- src/hooks/useUser.ts (new)
## Lint ResultsPASS: eslint cleanPASS: typecheck clean
## Issues Found
[CRITICAL] Unsanitized dangerouslySetInnerHTMLFile: src/components/UserCard.tsx:42Issue: User-controlled bio rendered as raw HTML.Why: XSS via stored script tags in user input.Fix: Sanitize with DOMPurify or render as text:```tsximport DOMPurify from "isomorphic-dompurify";<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(user.bio) }} />```
[HIGH] Effect cleanup missingFile: src/hooks/useUser.ts:18Issue: `fetch` call without AbortController; setState on unmounted component possible.Fix: Add AbortController and cleanup:```tsuseEffect(() => { const ac = new AbortController(); fetch(`/api/users/${id}`, { signal: ac.signal }) .then(r => r.json()) .then(setUser); return () => ac.abort();}, [id]);```
## Summary- CRITICAL: 1- HIGH: 1- MEDIUM: 0
Recommendation: FAIL: Block merge until CRITICAL issue is fixedApproval Criteria
| Status | Condition |
|---|---|
| PASS: Approve | No CRITICAL or HIGH issues |
| WARNING: Warning | Only MEDIUM issues (merge with caution) |
| FAIL: Block | CRITICAL or HIGH issues found |
Integration with Other Commands
- Run
/react-buildfirst if the build is broken - Run
/react-testto ensure component tests pass - Run
/react-reviewbefore merging - Use
/code-reviewfor non-React-specific concerns on the same PR
Related
- Agent:
agents/react-reviewer.md - Companion agent:
agents/typescript-reviewer.md(run alongside for TSX/JSX PRs) - Skills:
skills/react-patterns/,skills/react-testing/,skills/accessibility/ - Rules:
rules/react/