react-patterns
Use when implementing React 19 features, optimizing components, or choosing between Actions vs TanStack Query for mutations. Covers React Compiler optimization, Server Actions, Forms, and new hooks.
Best use case
react-patterns is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Use when implementing React 19 features, optimizing components, or choosing between Actions vs TanStack Query for mutations. Covers React Compiler optimization, Server Actions, Forms, and new hooks.
Teams using react-patterns should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/react-patterns/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How react-patterns Compares
| Feature / Agent | react-patterns | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Use when implementing React 19 features, optimizing components, or choosing between Actions vs TanStack Query for mutations. Covers React Compiler optimization, Server Actions, Forms, and new hooks.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
Related Guides
SKILL.md Source
# React 19 Patterns and Best Practices
Modern React 19 patterns leveraging the React Compiler, Server Actions, and new hooks.
## Compiler-Friendly Code
The React Compiler automatically optimizes components for performance. Write code that works well with it:
**Best Practices:**
- Keep components pure and props serializable
- Derive values during render (don't stash in refs unnecessarily)
- Keep event handlers inline unless they close over large mutable objects
- Verify compiler is working (DevTools ✨ badge)
- Opt-out problematic components with `"use no memo"` while refactoring
**Example - Pure Component:**
```typescript
// ✅ Compiler-friendly - pure function
function UserCard({ user }: { user: User }) {
const displayName = `${user.firstName} ${user.lastName}`
const isVIP = user.points > 1000
return (
<div>
<h2>{displayName}</h2>
{isVIP && <Badge>VIP</Badge>}
</div>
)
}
// ❌ Avoid - unnecessary effects
function UserCard({ user }: { user: User }) {
const [displayName, setDisplayName] = useState('')
useEffect(() => {
setDisplayName(`${user.firstName} ${user.lastName}`)
}, [user])
return <div><h2>{displayName}</h2></div>
}
```
**Verification:**
- Open React DevTools
- Look for "Memo ✨" badge on components
- If missing, component wasn't optimized (check for violations)
**Opt-Out When Needed:**
```typescript
'use no memo'
// Component code that can't be optimized yet
function ProblematicComponent() {
// ... code with compiler issues
}
```
## Actions & Forms
For SPA mutations, choose **one approach per feature**:
- **React 19 Actions:** `<form action={fn}>`, `useActionState`, `useOptimistic`
- **TanStack Query:** `useMutation`
Don't duplicate logic between both approaches.
### React 19 Actions (Form-Centric)
**Best for:**
- Form submissions
- Simple CRUD operations
- When you want form validation built-in
**Basic Action:**
```typescript
'use server' // Only if using SSR/RSC, omit for SPA
async function createTodoAction(formData: FormData) {
const text = formData.get('text') as string
// Validation
if (!text || text.length < 3) {
return { error: 'Text must be at least 3 characters' }
}
// API call
await api.post('/todos', { text })
// Revalidation happens automatically
return { success: true }
}
// Component
function TodoForm() {
return (
<form action={createTodoAction}>
<input name="text" required />
<button type="submit">Add Todo</button>
</form>
)
}
```
**With State (useActionState):**
```typescript
import { useActionState } from 'react'
function TodoForm() {
const [state, formAction, isPending] = useActionState(
createTodoAction,
{ error: null, success: false }
)
return (
<form action={formAction}>
{state.error && <ErrorMessage>{state.error}</ErrorMessage>}
<input name="text" required />
<button type="submit" disabled={isPending}>
{isPending ? 'Adding...' : 'Add Todo'}
</button>
</form>
)
}
```
**With Optimistic Updates (useOptimistic):**
```typescript
import { useOptimistic } from 'react'
function TaskList({ initialTodos }: { initialTodos: Todo[] }) {
const [optimisticTodos, addOptimisticTodo] = useOptimistic(
initialTodos,
(state, newTodo: string) => [
...state,
{ id: `temp-${Date.now()}`, text: newTodo, completed: false }
]
)
async function handleSubmit(formData: FormData) {
const text = formData.get('text') as string
addOptimisticTodo(text)
await createTodoAction(formData)
}
return (
<>
<ul>
{optimisticTodos.map(todo => (
<li key={todo.id} style={{ opacity: todo.id.startsWith('temp-') ? 0.5 : 1 }}>
{todo.text}
</li>
))}
</ul>
<form action={handleSubmit}>
<input name="text" required />
<button type="submit">Add</button>
</form>
</>
)
}
```
### TanStack Query Mutations (Preferred for SPAs)
**Best for:**
- Non-form mutations (e.g., button clicks)
- Complex optimistic updates with rollback
- Integration with existing Query cache
- More control over caching and invalidation
See **tanstack-query** skill for comprehensive mutation patterns.
**Quick Example:**
```typescript
import { useMutation, useQueryClient } from '@tanstack/react-query'
function useCre
ateTodo() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: (text: string) => api.post('/todos', { text }),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['todos'] })
},
})
}
// Usage
function TodoForm() {
const createTodo = useCreateTodo()
return (
<form onSubmit={(e) => {
e.preventDefault()
const formData = new FormData(e.currentTarget)
createTodo.mutate(formData.get('text') as string)
}}>
<input name="text" required />
<button type="submit" disabled={createTodo.isPending}>
{createTodo.isPending ? 'Adding...' : 'Add Todo'}
</button>
</form>
)
}
```
## The `use` Hook
The `use` hook unwraps Promises and Context, enabling new patterns.
**With Promises:**
```typescript
import { use, Suspense } from 'react'
function UserProfile({ userPromise }: { userPromise: Promise<User> }) {
const user = use(userPromise)
return <div>{user.name}</div>
}
// Usage
function App() {
const userPromise = fetchUser(1)
return (
<Suspense fallback={<Spinner />}>
<UserProfile userPromise={userPromise} />
</Suspense>
)
}
```
**With Context:**
```typescript
import { use, createContext } from 'react'
const ThemeContext = createContext<string>('light')
function Button() {
const theme = use(ThemeContext)
return <button className={theme}>Click me</button>
}
```
**When to Use:**
- Primarily useful with Suspense/data primitives and RSC (React Server Components)
- **For SPA-only apps**, prefer **TanStack Query + Router loaders** for data fetching
- `use` shines when you already have a Promise from a parent component
## Component Composition Patterns
**Compound Components:**
```typescript
// ✅ Good - composable, flexible
<Card>
<Card.Header>
<Card.Title>Dashboard</Card.Title>
</Card.Header>
<Card.Content>
{/* content */}
</Card.Content>
</Card>
// Implementation
function Card({ children }: { children: React.ReactNode }) {
return <div className="card">{children}</div>
}
Card.Header = function CardHeader({ children }: { children: React.ReactNode }) {
return <header className="card-header">{children}</header>
}
Card.Title = function CardTitle({ children }: { children: React.ReactNode }) {
return <h2 className="card-title">{children}</h2>
}
Card.Content = function CardContent({ children }: { children: React.ReactNode }) {
return <div className="card-content">{children}</div>
}
```
**Render Props (when needed):**
```typescript
function DataLoader<T>({
fetch,
render
}: {
fetch: () => Promise<T>
render: (data: T) => React.ReactNode
}) {
const { data } = useQuery({ queryKey: ['data'], queryFn: fetch })
if (!data) return <Spinner />
return <>{render(data)}</>
}
// Usage
<DataLoader
fetch={() => fetchUser(1)}
render={(user) => <UserCard user={user} />}
/>
```
## Error Boundaries
React 19 still requires class components for error boundaries (or use a library):
```typescript
import { Component, ReactNode } from 'react'
class ErrorBoundary extends Component<
{ children: ReactNode; fallback: ReactNode },
{ hasError: boolean }
> {
state = { hasError: false }
static getDerivedStateFromError() {
return { hasError: true }
}
componentDidCatch(error: Error, info: { componentStack: string }) {
console.error('Error caught:', error, info)
}
render() {
if (this.state.hasError) {
return this.props.fallback
}
return this.props.children
}
}
// Usage
<ErrorBoundary fallback={<ErrorFallback />}>
<App />
</ErrorBoundary>
```
**Or use react-error-boundary library:**
```typescript
import { ErrorBoundary } from 'react-error-boundary'
<ErrorBoundary
fallback={<div>Something went wrong</div>}
onError={(error, info) => console.error(error, info)}
>
<App />
</ErrorBoundary>
```
## Decision Guide: Actions vs Query Mutations
| Scenario | Recommendation |
|----------|---------------|
| Form submission with validation | React Actions |
| Button click mutation | TanStack Query |
| Needs optimistic updates + rollback | TanStack Query |
| Integrates with existing cache | TanStack Query |
| SSR/RSC application | React Actions |
| SPA with complex data flow | TanStack Query |
| Simple CRUD with forms | React Actions |
**Rule of Thumb:** For SPAs with TanStack Query already in use, prefer Query mutations for consistency. Only use Actions for form-heavy features where the form-centric API is beneficial.
## Related Skills
- **tanstack-query** - Server state with mutations and optimistic updates
- **core-principles** - Overall project structure
- **tooling-setup** - React Compiler configurationRelated Skills
data-extraction-patterns
Common patterns for extracting analytics data from GA4 and GSC with API handling
batching-patterns
Batch all related operations into single messages for maximum parallelism and performance. Use when launching multiple agents, reading multiple files, running parallel searches, optimizing workflow speed, or avoiding sequential execution bottlenecks. Trigger keywords - "batching", "parallel", "single message", "golden rule", "concurrent", "performance", "sequential bottleneck", "speed optimization".
ab-testing-patterns
A/B testing methodology for cold email optimization
plugin-sdk-patterns
Unified patterns and templates for creating consistent Claude Code plugins. Use when creating new plugins, designing plugin architecture, implementing builder patterns, or standardizing plugin structure. Trigger keywords - "plugin SDK", "plugin template", "plugin pattern", "builder pattern", "plugin structure", "new plugin", "plugin architecture".
react-typescript
Modern React 19+ patterns with TypeScript including function components, hooks, state management, TanStack Query integration, form handling with Zod, error boundaries, and performance optimization. Use when building React applications, implementing components, or setting up state management.
universal-patterns
Use when implementing language-agnostic patterns like layered architecture, dependency injection, error handling, or code organization principles across any technology stack.
database-patterns
Use when designing database schemas, implementing repository patterns, writing optimized queries, managing migrations, or working with indexes and transactions for SQL/NoSQL databases.
auth-patterns
Use when implementing authentication (JWT, sessions, OAuth), authorization (RBAC, ABAC), password hashing, MFA, or security best practices for backend services.
patterns
Common agent patterns and templates for Claude Code. Use when implementing agents to follow proven patterns for Tasks integration, quality checks, and external model invocation via claudish CLI.
test-skill
A test skill for validation testing. Use when testing skill parsing and validation logic.
bad-skill
This skill has invalid YAML in frontmatter
release
Plugin release process for MAG Claude Plugins marketplace. Covers version bumping, marketplace.json updates, git tagging, and common mistakes. Use when releasing new plugin versions or troubleshooting update issues.