React Patterns That Work Well with Claude Code

What Claude handles reliably, what needs more guidance, and how to get consistent results on component work.

React has a lot of flexibility, which means Claude Code can produce working code via several different approaches. The approaches aren't equally good. Here's what I've found works well and what needs more care.

Set conventions at session start

Before any React work:

React conventions for this codebase:
- Functional components only, no class components
- Custom hooks for all data fetching (useQuery pattern)
- State: useState for local, Zustand for shared
- No prop drilling beyond 2 levels — use context or state
- TypeScript strict mode, all props typed with interface
- Tailwind for styling, no CSS modules or styled-components

Without this, Claude will use whatever patterns it predicts you're using — and it's often wrong. This context eliminates component style drift across sessions.

Component prompts

The pattern that gets consistent results:

Write a [ComponentName] component. It should:
- Accept props: [list with types]
- Handle states: loading, error, empty, populated
- Use the existing [ComponentX] pattern from [file]
- Accessibility: keyboard navigation, ARIA labels for interactive elements

Don't handle data fetching inside the component — accept data as props.

The "accept data as props" constraint keeps components testable. Components that fetch their own data are harder to test and less reusable.

Custom hook patterns

Write a useX hook that:
- Fetches [data] from [endpoint]
- Returns: { data, loading, error, refetch }
- Handles cleanup on unmount
- Caches results for [duration]
- Uses the existing httpClient from lib/api.ts

Include types for the return value.

Hooks with consistent return shapes (data, loading, error, refetch) are composable. Claude will follow this pattern reliably when you specify it.

Where Claude needs more guidance

Performance optimization: React.memo, useMemo, useCallback. Claude will add these but sometimes adds them where they're unnecessary (premature optimization) or misses them where they matter. Be explicit: "Only memoize if there's a clear performance reason — explain the reason."

Form handling: Claude has opinions here. Specify your form library: "Use react-hook-form with zod validation. Don't use controlled components or manual onChange handlers."

Error boundaries: Claude often forgets these. Add to your template: "Every route-level component needs an error boundary. Write it."

Component review prompt

After Claude writes a component:

Review this component. Check:
1. Does it handle all states (loading, error, empty)?
2. Are there unnecessary re-renders?
3. Is the prop interface minimal (no unused props)?
4. Accessibility: can keyboard users interact with everything?
5. Are there any side effects in the render function?

Storybook and testing

Write a Storybook story for this component. Cover:
- Default state
- Loading state
- Error state
- Empty state
- Edge case: [specific edge case for this component]

Write tests that verify the component renders correctly for each story.

Stories and tests together make refactoring safe. This prompt generates both in one shot.


React-specific prompts and patterns are in the Agent Prompt Playbook. $29.