React + TypeScript + Vite SPA Rules
Modern React SPA conventions: hooks, Suspense, error boundaries, Vite tuning.
# CLAUDE.md — React + TypeScript + Vite
## Project structure
- `src/components/` — reusable components, server-agnostic
- `src/features/<feature>/` — feature-scoped components, hooks, types, services
- `src/lib/` — pure utilities, no React imports
- `src/hooks/` — shared custom hooks (one hook per file)
- `src/app/` — top-level routing and providers
- Co-locate tests next to the file (`Component.test.tsx`).
## TypeScript
- `strict: true` plus `noUncheckedIndexedAccess` and `exactOptionalPropertyTypes`.
- No `any`. Use `unknown` and narrow.
- Component props are an `interface`, not a `type` alias, when other components might extend them.
- Children: `children: React.ReactNode` for free-form, `children: React.ReactElement` for a single element.
## Components
- Function components only. No class components.
- Default to named exports. One component per file. The file name matches the component.
- Keep components under ~150 lines. Split by responsibility, not by size alone.
- Server-state, async work, and side effects belong in hooks — never inline `useEffect` for fetching.
## Hooks
- Custom hook names start with `use`. They return either an object (multiple values) or a single value — never both.
- Always specify the dep array. ESLint `react-hooks/exhaustive-deps` is `error`, not `warn`.
- `useEffect` is a last resort. Prefer derived state, `useMemo`, or moving logic to event handlers.
## State
- Local state with `useState`/`useReducer`.
- Cross-component state with React Context only when prop-drilling exceeds ~3 levels.
- Server state with TanStack Query (don't roll your own cache).
- Global UI state (modals, toasts) with Zustand or context — keep stores small and feature-local.
## Suspense & errors
- Wrap async boundaries in `<Suspense>` with a real fallback (skeletons match the layout).
- Wrap routes in `<ErrorBoundary>`. Each boundary owns a recovery action ("Retry", "Go home").
## Vite
- Pin Vite and `@vitejs/plugin-react` versions. Don't auto-update on every PR.
- Use `import.meta.env` (not `process.env`). Prefix public env vars with `VITE_`.
- Add `vitest` for tests. Reuse Vite's config — no separate Jest setup.
## Don't
- Don't put fetches in `useEffect`. Use TanStack Query or move to a Suspense data layer.
- Don't pass JSX as a prop just to defer rendering. Use `<Suspense>`.
- Don't disable lint rules to silence "missing dep" warnings — fix the underlying bug.
- Don't reach for `useCallback` / `useMemo` until profiling proves they help.
Other React templates
Next.js App Router + TypeScript Rules
Server Components, Server Actions, and TypeScript discipline for the Next.js App Router.
Next.js + Server Actions + Shadcn UI
Forms with Server Actions, Zod validation, and Shadcn UI primitives.
React Hooks Best Practices
Disciplined hook usage: deps arrays, custom hooks, refs, and effect minimalism.
React + TanStack Query
Server state with TanStack Query: caching, mutations, optimistic updates.
React + Redux Toolkit
Modern Redux with RTK, slices, and RTK Query for data fetching.