Files
everything-claude-code/commands/react-review.md
T
AlexisLeDain de135f61c7 fix(react): address PR #2024 review feedback
Critical:
- Remove undefined/.claude/session-aliases.json containing __proto__ prototype-pollution
  fixture committed by accident in a7333c14

High:
- agents/react-build-resolver.md: replace brittle `test -o $(grep -l ...)` and
  `test -a -n $(grep ...)` detection with explicit `{ ... || grep -q ...; }` so
  bundler detection no longer breaks when grep returns empty
- agents/react-build-resolver.md: drop hardcoded `npm i react@^19 react-dom@^19`
  remediation; replace with version-agnostic pair-upgrade note that honors the
  project's installed major (17/18/19) — surgical fix principle
- commands/react-review.md: guard `tsc --noEmit -p tsconfig.json` with
  `[ -f tsconfig.json ] &&` so the review skips cleanly on JS-only projects

Medium:
- rules/react/security.md: correct the React-18-blocks-javascript-URL claim
  (React only warns in dev; production navigation is not blocked)
- rules/react/security.md: correct CRA env-var exposure row (CRA exposes
  REACT_APP_*, NODE_ENV, PUBLIC_URL — not 'all' variables)
- skills/react-testing/SKILL.md: instantiate QueryClient once outside the
  wrapper closure so React Query cache survives re-renders (flaky-test fix)
- skills/react-testing/SKILL.md: restore console.error spy with mockRestore()
  in a try/finally so the mock does not leak across tests
- commands/react-test.md: switch outer example-session fence to 4 backticks
  so the inner ```tsx/```bash blocks don't prematurely terminate it
2026-05-21 15:45:47 +02:00

5.7 KiB

description
description
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

  1. Identify React Changes: Find modified .tsx/.jsx files (and React-containing .ts/.js files) via git diff
  2. Run Lint: Execute eslint with eslint-plugin-react-hooks and eslint-plugin-jsx-a11y
  3. Typecheck: Run tsc --noEmit or the project's canonical typecheck command
  4. Review React Lanes Only: Hook rules, RSC boundaries, accessibility, render performance, React-specific security
  5. Generate Report: Categorize issues by severity (CRITICAL / HIGH / MEDIUM)

When to Use

Use /react-review when:

  • A PR or commit touches .tsx/.jsx files
  • 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)

  • dangerouslySetInnerHTML with unsanitized input
  • href/src with unvalidated user URLs (javascript:, data:)
  • Server Action without input validation
  • Secret in client bundle (NEXT_PUBLIC_*, VITE_*, REACT_APP_*)
  • localStorage/sessionStorage for 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/useCallback deps (disabled exhaustive-deps without 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 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.

Example Usage

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:

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


## Approval 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-build` first if the build is broken
- Run `/react-test` to ensure component tests pass
- Run `/react-review` before merging
- Use `/code-review` for 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/`