skills/dotneet/claude-code-marketplace/typescript-react-reviewer

# typescript-react-reviewer

SKILL.md

# TypeScript + React 19 Code Review Expert

Expert code reviewer with deep knowledge of React 19's new features, TypeScript best practices, state management patterns, and common anti-patterns.

## Review Priority Levels

### 🚫 Critical (Block Merge)

These issues cause bugs, memory leaks, or architectural problems:

Issue | Why It's Critical
--- | ---
`useEffect` for derived state | Extra render cycle, sync bugs
Missing cleanup in `useEffect` | Memory leaks
Direct state mutation (`.push()`, `.splice()`) | Silent update failures
Conditional hook calls | Breaks Rules of Hooks
`key={index}` in dynamic lists | State corruption on reorder
`any` type without justification | Type safety bypass
`useFormStatus` in same component as `<form>` | Always returns false (React 19 bug)
Promise created inside render with `use()` | Infinite loop

### ⚠️ High Priority

Issue | Impact
--- | ---
Incomplete dependency arrays | Stale closures, missing updates
Props typed as `any` | Runtime errors
Unjustified `useMemo`/`useCallback` | Unnecessary complexity
Missing Error Boundaries | Poor error UX
Controlled input initialized with `undefined` | React warning

### 📝 Architecture/Style

Issue | Recommendation
--- | ---
Component > 300 lines | Split into smaller components
Prop drilling > 2-3 levels | Use composition or context
State far from usage | Colocate state
Custom hooks without `use` prefix | Follow naming convention

## Quick Detection Patterns

### useEffect Abuse (Most Common Anti-Pattern)

    // ❌ WRONG: Derived state in useEffect
    const [firstName, setFirstName] = useState('');
    const [fullName, setFullName] = useState('');
    useEffect(() => {
      setFullName(firstName + ' ' + lastName);
    }, [firstName, lastName]);

    // ✅ CORRECT: Compute during render
    const fullName = firstName + ' ' + lastName;

    // ❌ WRONG: Event logic in useEffect
    useEffect(() => {
      if (product.isInCart) showNotification('Added!');
    }, [product]);

    // ✅ CORRECT: Logic in event handler
    function handleAddToCart() {
      addToCart(product);
      showNotification('Added!');
    }

### React 19 Hook Mistakes

    // ❌ WRONG: useFormStatus in form component (always returns false)
    function Form() {
      const { pending } = useFormStatus();
      return <form action={submit}><button disabled={pending}>Send</button></form>;
    }

    // ✅ CORRECT: useFormStatus in child component
    function SubmitButton() {
      const { pending } = useFormStatus();
      return <button type="submit" disabled={pending}>Send</button>;
    }
    function Form() {
      return <form action={submit}><SubmitButton /></form>;
    }

    // ❌ WRONG: Promise created in render (infinite loop)
    function Component() {
      const data = use(fetch('/api/data')); // New promise every render!
    }

    // ✅ CORRECT: Promise from props or state
    function Component({ dataPromise }: { dataPromise: Promise<Data> }) {
      const data = use(dataPromise);
    }

### State Mutation Detection

    // ❌ WRONG: Mutations (no re-render)
    items.push(newItem);
    setItems(items);

    arr[i] = newValue;
    setArr(arr);

    // ✅ CORRECT: Immutable updates
    setItems([...items, newItem]);
    setArr(arr.map((x, idx) => idx === i ? newValue : x));

### TypeScript Red Flags

    // ❌ Red flags to catch
    const data: any = response;           // Unsafe any
    const items = arr[10];                // Missing undefined check
    const App: React.FC<Props> = () => {}; // Discouraged pattern

    // ✅ Preferred patterns
    const data: ResponseType = response;
    const items = arr[10]; // with noUncheckedIndexedAccess
    const App = ({ prop }: Props) => {};  // Explicit props

## Review Workflow

1. Scan for critical issues first - Check for the patterns in "Critical (Block Merge)" section
2. Check React 19 usage - See react19-patterns.md for new API patterns
3. Evaluate state management - Is state colocated? Server state vs client state separation?
4. Assess TypeScript safety - Generic components, discriminated unions, strict config
5. Review for maintainability - Component size, hook design, folder structure

## Reference Documents

For detailed patterns and examples:

- react19-patterns.md - React 19 new hooks (useActionState, useOptimistic, use), Server/Client Component boundaries
- antipatterns.md - Comprehensive anti-pattern catalog with fixes
- checklist.md - Full code review checklist for thorough reviews

## State Management Quick Guide

Data Type | Solution
--- | ---
Server/async data | TanStack Query (never copy to local state)
Simple global UI state | Zustand (~1KB, no Provider)
Fine-grained derived state | Jotai (~2.4KB)
Component-local state | useState/useReducer
Form state | React 19 useActionState

### TanStack Query Anti-Pattern

    // ❌ NEVER copy server data to local state
    const { data } = useQuery({ queryKey: ['todos'], queryFn: fetchTodos });
    const [todos, setTodos] = useState([]);
    useEffect(() => setTodos(data), [data]);

    // ✅ Query IS the source of truth
    const { data: todos } = useQuery({ queryKey: ['todos'], queryFn: fetchTodos });

## TypeScript Config Recommendations

    {
      "compilerOptions": {
        "strict": true,
        "noUncheckedIndexedAccess": true,
        "noImplicitReturns": true,
        "exactOptionalPropertyTypes": true
      }
    }

`noUncheckedIndexedAccess` is critical - it catches `arr[i]` returning undefined.

## Immediate Red Flags

When reviewing, flag these immediately:

Pattern | Problem | Fix
--- | --- | ---
`eslint-disable react-hooks/exhaustive-deps` | Hides stale closure bugs | Refactor logic
Component defined inside component | Remounts every render | Move outside
`useState(undefined)` for inputs | Uncontrolled warning | Use empty string
`React.FC` with generics | Generic inference breaks | Use explicit props
Barrel files (`index.ts`) in app code | Bundle bloat, circular deps | Direct imports

Weekly Installs
1.0K
Repository
dotneet/claude-code-marketplace
First Seen
Jan 21, 2026
Security Audits
Gen Agent Trust Hub Pass
Socket Pass
Snyk Pass
Installed on
opencode 851
gemini-cli 836
codex 817
github-copilot 807
kimi-cli 716
amp 713