commands/react-review.md
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.
.tsx/.jsx files (and React-containing .ts/.js files) via git diffeslint with eslint-plugin-react-hooks and eslint-plugin-jsx-a11ytsc --noEmit or the project's canonical typecheck commandUse /react-review when:
.tsx/.jsx filesFor pure .ts/.js changes with no React imports, use /code-review (general) or invoke typescript-reviewer directly.
/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.
dangerouslySetInnerHTML with unsanitized inputhref/src with unvalidated user URLs (javascript:, data:)NEXT_PUBLIC_*, VITE_*, REACT_APP_*)localStorage/sessionStorage for session tokensuseEffect/useMemo/useCallback deps (disabled exhaustive-deps without justification)key={index} in dynamic listsuseContext# 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 rules
npx eslint . --rule 'jsx-a11y/alt-text: error' \
--rule 'jsx-a11y/anchor-is-valid: error' \
--rule 'jsx-a11y/click-events-have-key-events: error'
# Supply-chain
npm audit
If 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.
User: /react-review
Agent:
# React Code Review Report
## Files Reviewed
- src/components/UserCard.tsx (modified)
- src/hooks/useUser.ts (new)
## Lint Results
PASS: eslint clean
PASS: typecheck clean
## Issues Found
[CRITICAL] Unsanitized dangerouslySetInnerHTML
File: src/components/UserCard.tsx:42
Issue: User-controlled bio rendered as raw HTML.
Why: XSS via stored script tags in user input.
Fix: Sanitize with DOMPurify or render as text:
```tsx
import DOMPurify from "isomorphic-dompurify";
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(user.bio) }} />
```
[HIGH] Effect cleanup missing
File: src/hooks/useUser.ts:18
Issue: `fetch` call without AbortController; setState on unmounted component possible.
Fix: Add AbortController and cleanup:
```ts
useEffect(() => {
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 fixed
| Status | Condition |
|---|---|
| PASS: Approve | No CRITICAL or HIGH issues |
| WARNING: Warning | Only MEDIUM issues (merge with caution) |
| FAIL: Block | CRITICAL or HIGH issues found |
/react-build first if the build is broken/react-test to ensure component tests pass/react-review before merging/code-review for non-React-specific concerns on the same PRagents/react-reviewer.mdagents/typescript-reviewer.md (run alongside for TSX/JSX PRs)skills/react-patterns/, skills/react-testing/, skills/accessibility/rules/react/