var e=[{file:`SKILL.md`,content:`---
name: react
description: "Comprehensive React development patterns — component architecture, React 19 APIs, Server Components, TypeScript integration, and performance optimization."
metadata:
  category: domain
  domain: react
  applicability: on-demand
  inputs: [codebase, requirements]
  outputs: [component-patterns, code]
  relatedSkills: [typescript, frontend-design]
---

# React

> Comprehensive React development patterns — component architecture, React 19 APIs, Server Components, TypeScript integration, and performance optimization. Synthesized from react-dev patterns, react-patterns (React 19), and Vercel React best practices.

## When to Use

**MANDATORY** for the Frontend agent on every React task. Also use when:
- Building React components, hooks, or pages
- Working with Server Components or Server Actions
- Optimizing React performance (re-renders, bundle size, data fetching)
- Reviewing React code for correctness and best practices

## Thinking Model

React is a **description language for UI**, not an imperative framework. Think in snapshots, not steps:
- "Given this state, what should the screen look like?" (declarative)
- NOT "When this happens, do these 5 things in order" (imperative)

The render function is a PURE function of (props, state) → JSX. Side effects live in clearly-marked boundaries (effects, event handlers, server actions).

**Server vs Client boundary** — the most common architectural mistake in modern React:
- Default to Server Components (zero JS shipped, direct data access)
- Add 'use client' only when you need: event handlers, useState/useEffect, browser APIs
- The boundary is a CONTRACT — server can render client, client CANNOT import server

Before coding, decide in this order:
1. **What is pure UI derivation?** Keep it in render.
2. **What is interaction state?** Keep it in the smallest client boundary.
3. **What is data loading or mutation?** Prefer server.
4. **What is side effect vs event response?** Effects synchronize with outside systems; event handlers respond to user intent.

## Decision Flow

When implementing a React feature, follow this order:

1. **Server or Client?**
  - If it needs browser APIs, event handlers, or local interaction state → Client Component.
  - Everything else starts as a Server Component.
  - Keep the client boundary as small as possible: interactive leaf, server parent.

2. **Derived state or stored state?**
  - If a value can be computed from props/state during render, do NOT store it.
  - Store only user input, async status, or state you cannot recompute cheaply or correctly.

3. **Data loading location?**
  - Initial fetch on server.
  - Client refetch/cache only when data must stay live after hydration or respond to client events.

4. **Mutation path?**
  - Forms and mutations: Server Action + validation.
  - Use \`useActionState\` for submission state/errors.
  - Add \`useOptimistic\` only when instant feedback materially improves UX.

5. **Effect or not?**
  - If synchronizing with DOM, network subscription, timer, or external API → effect.
  - If reacting to user input → event handler.
  - If deriving view state → render logic, not effect.

6. **Error and loading boundaries?**
  - Rendering latency → \`<Suspense>\` with a real skeleton.
  - Render failures → Error Boundary.
  - Mutation failures → return structured errors from the Server Action.

7. **Performance pass?**
  - Start with correct boundaries and minimal client JS.
  - Then rely on React Compiler if enabled.
  - Only then add manual memoization, virtualization, or code splitting where profiling justifies it.

8. **Extraction pass?**
  - Business rules → hooks, utilities, or server functions.
  - Components stay focused on describing UI.

## NEVER

- **NEVER use \`useEffect\` for derived state** — if you can compute it from props/state, compute it inline or with \`useMemo\`. Effects for derivation cause extra renders and race conditions.
- **NEVER put business logic in components** — components are UI description, not business rules. Extract logic to hooks, utilities, or server functions.
- **NEVER use \`any\` to silence TypeScript in component props** — use \`unknown\` and narrow, or fix the actual type. \`any\` in props infects the entire component tree.
- **NEVER create a context for state that only one component reads** — prop drilling 2-3 levels is fine. Context adds re-render cost to EVERY consumer.
- **NEVER \`await\` inside \`useEffect\` directly** — use an inner async function or a data-fetching library. Direct await creates unhandled promise rejections and races.
- **NEVER conditionally call hooks** — hooks must be called in the same order every render. If you need conditional logic, move it INSIDE the hook.
- **NEVER spread props onto DOM elements without filtering** — \`{...props}\` passes unknown attributes to the DOM, causing console warnings and potential XSS vectors.
- **NEVER render a list without a stable key** — index-as-key causes state corruption on reorder. Use a domain ID or generate a stable key from content.

## React 19 Quick Reference

- \`ref\` as prop — no \`forwardRef\` wrapper for common cases
- \`use()\` — read promises/context during render
- \`useActionState\` + \`<form action>\` — form mutations with server actions
- \`useOptimistic\` + \`useTransition\` — optimistic and non-urgent updates
- Server Components / Server Actions — default to server, opt into client only when needed

## Component Patterns

### Extend Native Elements
\`\`\`tsx
type ButtonProps = React.ComponentProps<"button"> & {
  variant?: "primary" | "secondary" | "ghost";
  size?: "sm" | "md" | "lg";
};

function Button({ variant = "primary", size = "md", className, ...props }: ButtonProps) {
  return <button className={cn(variants[variant], sizes[size], className)} {...props} />;
}
\`\`\`

### Discriminated Union Props
\`\`\`tsx
type ModalProps =
  | { variant: "alert"; message: string; onConfirm: () => void }
  | { variant: "form"; children: React.ReactNode; onSubmit: (data: FormData) => void };

function Modal(props: ModalProps) {
  switch (props.variant) {
    case "alert": return <AlertModal {...props} />;
    case "form": return <FormModal {...props} />;
  }
}
\`\`\`

### Generic Components
\`\`\`tsx
type TableProps<T> = {
  data: T[];
  columns: { key: keyof T; header: string; render?: (value: T[keyof T], row: T) => React.ReactNode }[];
  onRowClick?: (row: T) => void;
};

function Table<T extends Record<string, unknown>>({ data, columns, onRowClick }: TableProps<T>) {
  // ...
}
\`\`\`

### Children Typing
- Specific children: \`React.ReactElement<TabProps>[]\`
- Render prop: \`(data: T) => React.ReactNode\`
- Text-only API: \`string\`

## Ref as Prop (React 19)

\`\`\`tsx
function Input({ ref, ...props }: React.ComponentProps<"input">) {
  return <input ref={ref} {...props} />;
}
\`\`\`

Callback refs can return cleanup functions in React 19. Use that for measurement/subscription teardown instead of scattering cleanup elsewhere.

## Server Components & Actions

### Server Component (default — no directive needed)
\`\`\`tsx
import { db } from "@/lib/db";

export default async function UsersPage() {
  const users = await db.query.users.findMany();
  return <UserList users={users} />;
}
\`\`\`

### Client Component (explicit opt-in)
\`\`\`tsx
"use client";
import { useState } from "react";

export function Counter({ initialCount }: { initialCount: number }) {
  const [count, setCount] = useState(initialCount);
  return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}
\`\`\`

### Server Action with Form
\`\`\`tsx
"use server";
import { z } from "zod";

const schema = z.object({ name: z.string().min(1), email: z.string().email() });

export async function createUser(_prev: unknown, formData: FormData) {
  const result = schema.safeParse(Object.fromEntries(formData));
  if (!result.success) return { error: result.error.flatten().fieldErrors };
  await saveUser(result.data);
  return { success: true };
}
\`\`\`

\`\`\`tsx
"use client";
import { useActionState } from "react";
import { createUser } from "./actions";

export function CreateUserForm() {
  const [state, action, isPending] = useActionState(createUser, null);
  return (
    <form action={action}>
      <input name="name" required />
      <input name="email" type="email" required />
      <button disabled={isPending}>{isPending ? "Creating..." : "Create"}</button>
    </form>
  );
}
\`\`\`

### Optimistic Updates
\`\`\`tsx
"use client";
import { useOptimistic } from "react";

function TodoList({ todos, addTodo }: { todos: Todo[]; addTodo: (text: string) => Promise<void> }) {
  const [optimisticTodos, addOptimistic] = useOptimistic(todos, (state, text: string) => [
    ...state,
    { id: "temp", text, pending: true },
  ]);

  async function handleAdd(formData: FormData) {
    const text = formData.get("text") as string;
    addOptimistic(text);
    await addTodo(text);
  }

  return (
    <form action={handleAdd}>
      <input name="text" />
      <button type="submit">Add</button>
      <ul>
        {optimisticTodos.map(t => (
          <li key={t.id} style={{ opacity: t.pending ? 0.5 : 1 }}>{t.text}</li>
        ))}
      </ul>
    </form>
  );
}
\`\`\`

## Event Handler Types

Prefer exact DOM event types at the boundary: \`MouseEvent<HTMLButtonElement>\`, \`ChangeEvent<HTMLInputElement>\`, \`FormEvent<HTMLFormElement>\`. If you start with a broad \`SyntheticEvent\`, you are probably typing too late.

## Hooks Typing

- \`useState\` — model UI state with explicit unions, not booleans that drift out of sync
- \`useRef<HTMLInputElement>(null)\` for DOM refs; mutable refs only for non-render state
- \`useReducer\` — discriminated union actions when state transitions are non-trivial
- Custom hooks returning tuples should use \`as const\`
- Context consumers should null-guard and fail fast outside their provider

## Performance Rules

### Prevent Async Waterfalls
\`\`\`tsx
const user = await getUser(id);
const posts = await getPosts(user.id);

const [user, posts] = await Promise.all([getUser(id), getPosts(id)]);
\`\`\`

### Performance Checklist
- Server Components first; ship less JS before optimizing JS
- \`<Suspense>\` + streaming for slow server work
- SWR/React Query when client data must stay fresh after hydration
- React Compiler first, then manual \`useMemo\`/\`useCallback\` only when profiling proves need
- Virtualize lists >100 items; defer heavy client work with \`useDeferredValue\`
- Lazy load below-fold components; prefer named imports for tree-shaking
- Avoid passing large objects across the server/client boundary

`}];export{e as default};