--- name: react-dev version: 1.0.0 description: This skill should be used when building React components with TypeScript, typing hooks, handling events, or when React TypeScript, React 19, Server Components are mentioned. Covers type-safe patterns for React 18-19 including generic components, proper event typing, and routing integration (TanStack Router, React Router). --- # React TypeScript Type-safe React = compile-time guarantees = confident refactoring. - Building typed React components - Implementing generic components - Typing event handlers, forms, refs - Using React 19 features (Actions, Server Components, use()) - Router integration (TanStack Router, React Router) - Custom hooks with proper typing NOT for: non-React TypeScript, vanilla JS React React 19 breaking changes require migration. Key patterns: **ref as prop** - forwardRef deprecated: ```typescript // React 19 - ref as regular prop type ButtonProps = { ref?: React.Ref; } & React.ComponentPropsWithoutRef<'button'>; function Button({ ref, children, ...props }: ButtonProps) { return ; } ``` **useActionState** - replaces useFormState: ```typescript import { useActionState } from 'react'; type FormState = { errors?: string[]; success?: boolean }; function Form() { const [state, formAction, isPending] = useActionState(submitAction, {}); return
...
; } ``` **use()** - unwraps promises/context: ```typescript function UserProfile({ userPromise }: { userPromise: Promise }) { const user = use(userPromise); // Suspends until resolved return
{user.name}
; } ``` See [react-19-patterns.md](references/react-19-patterns.md) for useOptimistic, useTransition, migration checklist.
**Props** - extend native elements: ```typescript type ButtonProps = { variant: 'primary' | 'secondary'; } & React.ComponentPropsWithoutRef<'button'>; function Button({ variant, children, ...props }: ButtonProps) { return ; } ``` **Children typing**: ```typescript type Props = { children: React.ReactNode; // Anything renderable icon: React.ReactElement; // Single element render: (data: T) => React.ReactNode; // Render prop }; ``` **Discriminated unions** for variant props: ```typescript type ButtonProps = | { variant: 'link'; href: string } | { variant: 'button'; onClick: () => void }; function Button(props: ButtonProps) { if (props.variant === 'link') { return Link; } return ; } ``` Use specific event types for accurate target typing: ```typescript // Mouse function handleClick(e: React.MouseEvent) { e.currentTarget.disabled = true; } // Form function handleSubmit(e: React.FormEvent) { e.preventDefault(); const formData = new FormData(e.currentTarget); } // Input function handleChange(e: React.ChangeEvent) { console.log(e.target.value); } // Keyboard function handleKeyDown(e: React.KeyboardEvent) { if (e.key === 'Enter') e.currentTarget.blur(); } ``` See [event-handlers.md](references/event-handlers.md) for focus, drag, clipboard, touch, wheel events. **useState** - explicit for unions/null: ```typescript const [user, setUser] = useState(null); const [status, setStatus] = useState<'idle' | 'loading'>('idle'); ``` **useRef** - null for DOM, value for mutable: ```typescript const inputRef = useRef(null); // DOM - use ?. const countRef = useRef(0); // Mutable - direct access ``` **useReducer** - discriminated unions for actions: ```typescript type Action = | { type: 'increment' } | { type: 'set'; payload: number }; function reducer(state: State, action: Action): State { switch (action.type) { case 'set': return { ...state, count: action.payload }; default: return state; } } ``` **Custom hooks** - tuple returns with as const: ```typescript function useToggle(initial = false) { const [value, setValue] = useState(initial); const toggle = () => setValue(v => !v); return [value, toggle] as const; } ``` **useContext** - null guard pattern: ```typescript const UserContext = createContext(null); function useUser() { const user = useContext(UserContext); if (!user) throw new Error('useUser outside UserProvider'); return user; } ``` See [hooks.md](references/hooks.md) for useCallback, useMemo, useImperativeHandle, useSyncExternalStore. Generic components infer types from props - no manual annotations at call site. **Pattern** - keyof T for column keys, render props for custom rendering: ```typescript type Column = { key: keyof T; header: string; render?: (value: T[keyof T], item: T) => React.ReactNode; }; type TableProps = { data: T[]; columns: Column[]; keyExtractor: (item: T) => string | number; }; function Table({ data, columns, keyExtractor }: TableProps) { return ( {columns.map(col => )} {data.map(item => ( {columns.map(col => ( ))} ))}
{col.header}
{col.render ? col.render(item[col.key], item) : String(item[col.key])}
); } ``` **Constrained generics** for required properties: ```typescript type HasId = { id: string | number }; function List({ items }: { items: T[] }) { return
    {items.map(item =>
  • ...
  • )}
; } ``` See [generic-components.md](examples/generic-components.md) for Select, List, Modal, FormField patterns.
React 19 Server Components run on server, can be async. **Async data fetching**: ```typescript export default async function UserPage({ params }: { params: { id: string } }) { const user = await fetchUser(params.id); return
{user.name}
; } ``` **Server Actions** - 'use server' for mutations: ```typescript 'use server'; export async function updateUser(userId: string, formData: FormData) { await db.user.update({ where: { id: userId }, data: { ... } }); revalidatePath(`/users/${userId}`); } ``` **Client + Server Action**: ```typescript 'use client'; import { useActionState } from 'react'; import { updateUser } from '@/actions/user'; function UserForm({ userId }: { userId: string }) { const [state, formAction, isPending] = useActionState( (prev, formData) => updateUser(userId, formData), {} ); return
...
; } ``` **use() for promise handoff**: ```typescript // Server: pass promise without await async function Page() { const userPromise = fetchUser('123'); return ; } // Client: unwrap with use() 'use client'; function UserProfile({ userPromise }: { userPromise: Promise }) { const user = use(userPromise); return
{user.name}
; } ``` See [server-components.md](examples/server-components.md) for parallel fetching, streaming, error boundaries.
Both TanStack Router and React Router v7 provide type-safe routing solutions. **TanStack Router** - Compile-time type safety with Zod validation: ```typescript import { createRoute } from '@tanstack/react-router'; import { z } from 'zod'; const userRoute = createRoute({ path: '/users/$userId', component: UserPage, loader: async ({ params }) => ({ user: await fetchUser(params.userId) }), validateSearch: z.object({ tab: z.enum(['profile', 'settings']).optional(), page: z.number().int().positive().default(1), }), }); function UserPage() { const { user } = useLoaderData({ from: userRoute.id }); const { tab, page } = useSearch({ from: userRoute.id }); const { userId } = useParams({ from: userRoute.id }); } ``` **React Router v7** - Automatic type generation with Framework Mode: ```typescript import type { Route } from "./+types/user"; export async function loader({ params }: Route.LoaderArgs) { return { user: await fetchUser(params.userId) }; } export default function UserPage({ loaderData }: Route.ComponentProps) { const { user } = loaderData; // Typed from loader return

{user.name}

; } ``` See [tanstack-router.md](references/tanstack-router.md) for TanStack patterns and [react-router.md](references/react-router.md) for React Router patterns.
ALWAYS: - Specific event types (MouseEvent, ChangeEvent, etc) - Explicit useState for unions/null - ComponentPropsWithoutRef for native element extension - Discriminated unions for variant props - as const for tuple returns - ref as prop in React 19 (no forwardRef) - useActionState for form actions - Type-safe routing patterns (see routing section) NEVER: - any for event handlers - JSX.Element for children (use ReactNode) - forwardRef in React 19+ - useFormState (deprecated) - Forget null handling for DOM refs - Mix Server/Client components in same file - Await promises when passing to use() - [hooks.md](references/hooks.md) - useState, useRef, useReducer, useContext, custom hooks - [event-handlers.md](references/event-handlers.md) - all event types, generic handlers - [react-19-patterns.md](references/react-19-patterns.md) - useActionState, use(), useOptimistic, migration - [generic-components.md](examples/generic-components.md) - Table, Select, List, Modal patterns - [server-components.md](examples/server-components.md) - async components, Server Actions, streaming - [tanstack-router.md](references/tanstack-router.md) - TanStack Router typed routes, search params, navigation - [react-router.md](references/react-router.md) - React Router v7 loaders, actions, type generation, forms