Cursor Rules for React Projects
React has dozens of ways to do the same thing. Here's how to encode your team's decisions into .cursor/rules so Cursor stops guessing.
The component consistency problem
React gives you enormous flexibility -functional components, class components, HOCs, render props, Context, hooks. Cursor will write whichever pattern it thinks fits, often mixing styles within a single session. Without rules, you get a codebase where components are inconsistently structured, props aren't typed, and hooks are used in ways that cause unnecessary re-renders.
Component pattern rules
Decide on your conventions once and encode them. The most impactful: one component per file, named exports only (no default exports -they make refactoring harder), props typed with interfaces, no inline anonymous function callbacks as props (they cause re-renders), and a consistent file structure within component files.
Ready-to-use React rules
Place this at .cursor/rules/react.mdc.
---
description: React component and hooks conventions
globs: ["**/*.tsx", "src/components/**", "src/hooks/**"]
alwaysApply: true
---
# React Rules
## Components
- One component per file. File name matches component name in kebab-case.
- Named exports only. Never default export a component.
- Props typed with an interface: interface ButtonProps { ... }
- No anonymous function callbacks as props (causes re-renders). Extract to handleX variables.
- Component file order: imports → interface → component → helper functions → export.
## Hooks
- Custom hooks live in src/hooks/ with a use prefix (useAuth.ts, useDebounce.ts).
- Never call hooks conditionally or in loops.
- useEffect: always add dependency array. Comment why each dependency is included.
- Prefer custom hooks over repeating logic in multiple components.
## State Management
- useState for local UI state (modal open, form field value).
- Context for low-frequency global state (theme, auth user).
- Zustand for complex shared state (do not add unless already in project).
- Never store server data in state -use a data-fetching library's cache.
## Performance
- Wrap expensive calculations in useMemo with a comment on why.
- Wrap callbacks passed to child components in useCallback if child is memoized.
- Do not over-optimize -profile before adding memoization.
## Error Handling
- Every async operation needs error state. No silent failures.
- Use error boundaries for component subtrees with risky renders.