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.