Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Use when building React 18+ applications in .jsx or .tsx files, Next.js App Router projects, or create-react-app setups. Creates components, implements custom hooks, debugs rendering issues, migrates class components to functional, and implements state management. Invoke for Server Components, Suspense boundaries, useActionState forms, performance optimization, or React 19 features.
.claude/skills/jeffallan-react-expert/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-03 | ✓→✗ | ▼ Worse | 84% | 0% |
| case-23 | ✓→✗ | ▼ Worse | 78% | 0% |
| case-01 | ✓→✓ | = Same ✓ | 29% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 30% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 88% | 0% |
Senior React specialist with deep expertise in React 19, Server Components, and production-grade application architecture.
use()tsc --noEmit; if it fails, review reported errors, fix all type issues, and re-run until clean before proceedingLoad detailed guidance based on context:
| Topic | Reference | Load When | |-------|-----------|-----------| | Server Components | references/server-components.md | RSC patterns, Next.js App Router | | React 19 | references/react-19-features.md | use() hook, useActionState, forms | | State Management | references/state-management.md | Context, Zustand, Redux, TanStack | | Hooks | references/hooks-patterns.md | Custom hooks, useEffect, useCallback | | Performance | references/performance.md | memo, lazy, virtualization | | Testing | references/testing-react.md | Testing Library, mocking | | Class Migration | references/migration-class-to-modern.md | Converting class components to hooks/RSC |
tsx// app/users/page.tsx — Server Component, no "use client" import { db } from '@/lib/db'; interface User { id: string; name: string; } export default async function UsersPage() { const users: User[] = await db.user.findMany(); return ( <ul> {users.map((user) => ( <li key={user.id}>{user.name}</li> ))} </ul> ); }
useActionStatetsx'use client'; import { useActionState } from 'react'; async function submitForm(_prev: string, formData: FormData): Promise<string> { const name = formData.get('name') as string; // perform server action or fetch return `Hello, ${name}!`; } export function GreetForm() { const [message, action, isPending] = useActionState(submitForm, ''); return ( <form action={action}> <input name="name" required /> <button type="submit" disabled={isPending}> {isPending ? 'Submitting…' : 'Submit'} </button> {message && <p>{message}</p>} </form> ); }
tsximport { useState, useEffect } from 'react'; function useWindowWidth(): number { const [width, setWidth] = useState(() => window.innerWidth); useEffect(() => { const handler = () => setWidth(window.innerWidth); window.addEventListener('resize', handler); return () => window.removeEventListener('resize', handler); // cleanup }, []); return width; }
key props correctly (stable, unique identifiers)When implementing React features, provide:
React 19, Server Components, use() hook, Suspense, TypeScript, TanStack Query, Zustand, Redux Toolkit, React Router, React Testing Library, Vitest/Jest, Next.js App Router, accessibility (WCAG)
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | pass→pass | 13,009 | 11,921 | -8% | 1 | 1 | 0% | 2,960 | 3,821 | +29% | 0 | 0 | — |
case-02 | pass→pass | 17,363 | 17,817 | +3% | 1 | 1 | 0% | 3,753 | 4,864 | +30% | 0 | 0 | — |
case-03 | pass→fail | 12,428 | 14,997 | +21% | 1 | 1 | 0% | 2,556 | 4,702 | +84% | 0 | 0 | — |
case-04 | pass→pass | 9,178 | 12,913 | +41% | 1 | 1 | 0% | 2,059 | 3,865 | +88% | 0 | 0 | — |
case-05 | pass→pass | 14,900 | 16,326 | +10% | 1 | 1 | 0% | 3,082 | 4,757 | +54% | 0 | 0 | — |
case-06 | pass→pass | 14,073 | 14,782 | +5% | 1 | 1 | 0% | 2,563 | 3,643 | +42% | 0 | 0 | — |
case-07 | pass→pass | 22,498 | 21,905 | -3% | 1 | 1 | 0% | 4,670 | 6,556 | +40% | 0 | 0 | — |
case-08 | pass→pass | 29,401 | 28,211 | -4% | 1 | 1 | 0% | 6,002 | 6,844 | +14% | 0 | 0 | — |
case-09 | fail→fail | 17,551 | 14,360 | -18% | 1 | 1 | 0% | 3,943 | 3,756 | -5% | 0 | 0 | — |
case-10 | pass→pass | 21,145 | 21,735 | +3% | 1 | 1 | 0% | 4,971 | 6,492 | +31% | 0 | 0 | — |
case-11 | pass→pass | 7,299 | 4,516 | -38% | 1 | 1 | 0% | 1,245 | 1,794 | +44% | 0 | 0 | — |
case-12 | pass→pass | 21,493 | 18,595 | -13% | 1 | 1 | 0% | 4,521 | 5,255 | +16% | 0 | 0 | — |
case-13 | pass→pass | 17,825 | 17,255 | -3% | 1 | 1 | 0% | 4,361 | 4,820 | +11% | 0 | 0 | — |
case-14 | pass→pass | 14,402 | 16,551 | +15% | 1 | 1 | 0% | 2,951 | 4,640 | +57% | 0 | 0 | — |
case-15 | pass→pass | 13,007 | 11,867 | -9% | 1 | 1 | 0% | 2,780 | 3,643 | +31% | 0 | 0 | — |
case-16 | pass→pass | 12,426 | 10,026 | -19% | 1 | 1 | 0% | 2,592 | 3,244 | +25% | 0 | 0 | — |
case-17 | pass→pass | 22,953 | 26,778 | +17% | 1 | 1 | 0% | 5,162 | 6,987 | +35% | 0 | 0 | — |
case-18 | pass→pass | 16,633 | 17,279 | +4% | 1 | 1 | 0% | 3,526 | 5,133 | +46% | 0 | 0 | — |
case-19 | pass→pass | 16,380 | 12,724 | -22% | 1 | 1 | 0% | 3,251 | 3,911 | +20% | 0 | 0 | — |
case-20 | pass→pass | 7,818 | 8,834 | +13% | 1 | 1 | 0% | 1,285 | 2,619 | +104% | 0 | 0 | — |
case-21 | pass→pass | 11,372 | 9,780 | -14% | 1 | 1 | 0% | 2,685 | 3,300 | +23% | 0 | 0 | — |
case-22 | pass→pass | 7,777 | 7,431 | -4% | 1 | 1 | 0% | 1,515 | 2,391 | +58% | 0 | 0 | — |
case-23 | pass→fail | 7,951 | 9,156 | +15% | 1 | 1 | 0% | 1,627 | 2,899 | +78% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of -67 percentage points is the difference between those two pass rates over the 23 comparable cases. 2 cases got worse with the skill loaded, and they are included in that figure.
Other measured skills in the registry, with their headline benchmark lift.