Skip to main content

react-dev

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 TanStack Router integration.

Informations de source

Dépôt
outfitter-dev/agents
Dernière activité de la source
27 janvier 2026 à 15:45
Langue détectée de SKILL.md
anglais
Étoiles
28
Forks
1

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Explorateur de fichiers
7 fichiers

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
react-dev
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 TanStack Router integration.
metadata
{"version":"1.0.0"}
# React TypeScript Type-safe React = compile-time guarantees = confident refactoring. <when_to_use> - Building typed React components - Implementing generic components - Typing event handlers, forms, refs - Using React 19 features (Actions, Server Components, use()) - TanStack Router integration - Custom hooks with proper typing NOT for: non-React TypeScript, vanilla JS React </when_to_use> <react_19_changes> 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<HTMLButtonElement>; } & React.ComponentPropsWithoutRef<'button'>; function Button({ ref, children, ...props }: ButtonProps) { return <button ref={ref} {...props}>{children}</button>; } ``` **useActionState** - replaces useFormState: ```typescript import { useActionState } from 'react'; type FormState = { errors?: string[]; success?: boolean }; function Form() { const [state, formAction, isPending] = useActionState(submitAction, {}); return <form action={formAction}>...</form>; } ``` **use()** - unwraps promises/context: ```typescript function UserProfile({ userPromise }: { userPromise: Promise<User> }) { const user = use(userPromise); // Suspends until resolved return <div>{user.name}</div>; } ``` See [react-19-patterns.md](references/react-19-patterns.md) for useOptimistic, useTransition, migration checklist. </react_19_changes> <component_patterns> **Props** - extend native elements: ```typescript type ButtonProps = { variant: 'primary' | 'secondary'; } & React.ComponentPropsWithoutRef<'button'>; function Button({ variant, children, ...props }: ButtonProps) { return <button className={variant} {...props}>{children}</button>; } ``` **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 <a href={props.href}>Link</a>; } return <button onClick={props.onClick}>Button</button>; } ``` </component_patterns> <event_handlers> Use specific event types for accurate target typing: ```typescript // Mouse function handleClick(e: React.MouseEvent<HTMLButtonElement>) { e.currentTarget.disabled = true; } // Form function handleSubmit(e: React.FormEvent<HTMLFormElement>) { e.preventDefault(); const formData = new FormData(e.currentTarget); } // Input function handleChange(e: React.ChangeEvent<HTMLInputElement>) { console.log(e.target.value); } // Keyboard function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) { if (e.key === 'Enter') e.currentTarget.blur(); } ``` See [event-handlers.md](references/event-handlers.md) for focus, drag, clipboard, touch, wheel events. </event_handlers> <hooks_typing> **useState** - explicit for unions/null: ```typescript const [user, setUser] = useState<User | null>(null); const [status, setStatus] = useState<'idle' | 'loading'>('idle'); ``` **useRef** - null for DOM, value for mutable: ```typescript const inputRef = useRef<HTMLInputElement>(null); // DOM - use ?. const countRef = useRef<number>(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<User | null>(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. </hooks_typing> <generic_components> 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<T> = { key: keyof T; header: string; render?: (value: T[keyof T], item: T) => React.ReactNode; }; type TableProps<T> = { data: T[]; columns: Column<T>[]; keyExtractor: (item: T) => string | number; }; function Table<T>({ data, columns, keyExtractor }: TableProps<T>) { return ( <table> <thead> <tr>{columns.map(col => <th key={String(col.key)}>{col.header}</th>)}</tr> </thead> <tbody> {data.map(item => ( <tr key={keyExtractor(item)}> {columns.map(col => ( <td key={String(col.key)}> {col.render ? col.render(item[col.key], item) : String(item[col.key])} </td> ))} </tr> ))} </tbody> </table> ); } ``` **Constrained generics** for required properties: ```typescript type HasId = { id: string | number }; function List<T extends HasId>({ items }: { items: T[] }) { return <ul>{items.map(item => <li key={item.id}>...</li>)}</ul>; } ``` See [generic-components.md](examples/generic-components.md) for Select, List, Modal, FormField patterns. </generic_components> <server_components> 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 <div>{user.name}</div>; } ``` **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 <form action={formAction}>...</form>; } ``` **use() for promise handoff**: ```typescript // Server: pass promise without await async function Page() { const userPromise = fetchUser('123'); return <UserProfile userPromise={userPromise} />; } // Client: unwrap with use() 'use client'; function UserProfile({ userPromise }: { userPromise: Promise<User> }) { const user = use(userPromise); return <div>{user.name}</div>; } ``` See [server-components.md](examples/server-components.md) for parallel fetching, streaming, error boundaries. </server_components> <tanstack_integration> TanStack Router = type-safe routes, params, search params, loader data. **Route 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), }), }); ``` **Typed hooks**: ```typescript function UserPage() { const { user } = useLoaderData({ from: userRoute.id }); const { tab, page } = useSearch({ from: userRoute.id }); const { userId } = useParams({ from: userRoute.id }); } ``` **Type-safe navigation**: ```typescript navigate({ to: '/users/$userId', params: { userId }, search: { tab: 'profile' }, // Type-checked }); ``` See [tanstack-router.md](references/tanstack-router.md) for nested routes, beforeLoad, error handling, React Query integration. </tanstack_integration> <rules> 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 - Zod validation for TanStack Router search params 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() </rules> <references> - [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) - typed routes, search params, navigation </references>
Voir sur GitHub