React Production Engineering
Complete methodology for building production-grade React applications with architecture decisions, component design, state management, performance optimization, testing, and deployment.
安装 / 下载方式
TotalClaw CLI推荐
totalclaw install clawskills:1kalin~afrexai-react-productioncURL直接下载,无需登录
curl -fsSL https://skills.taituai.com/api/skills/clawskills%3A1kalin~afrexai-react-production/file -o afrexai-react-production.mdGit 仓库获取源码
git clone https://github.com/openclaw/skills/commit/8f51b22d8d64574d7f4975065b3b07678069cfa1# React Production Engineering
Complete methodology for building production-grade React applications. Covers architecture decisions, component design, state management, performance optimization, testing, and deployment — not just API reference, but engineering methodology with decision frameworks, templates, and scoring systems.
## Phase 1: Architecture Assessment
### Quick Health Check (score /16)
- [ ] Component tree depth < 6 levels (+2)
- [ ] No prop drilling past 2 levels (+2)
- [ ] Bundle size < 200KB gzipped (+2)
- [ ] LCP < 2.5s on 4G (+2)
- [ ] Test coverage > 70% on business logic (+2)
- [ ] Zero `any` types in production code (+2)
- [ ] No direct DOM manipulation (+2)
- [ ] Consistent error boundaries (+2)
### Architecture Brief
```yaml
project:
name: ""
type: "" # spa | ssr | hybrid | static
framework: "" # next | remix | vite-spa | astro
scale: "" # small (<20 routes) | medium (20-100) | large (100+)
team_size: "" # solo | small (2-5) | medium (6-15) | large (15+)
current_state:
react_version: "" # 18 | 19
typescript: true
router: "" # react-router | next-app | tanstack-router
state_management: "" # useState | zustand | jotai | redux | tanstack-query
styling: "" # tailwind | css-modules | styled-components | vanilla-extract
testing: "" # vitest | jest | playwright | cypress
ci_cd: "" # github-actions | gitlab-ci | vercel
pain_points: []
goals: []
```
### Framework Selection Decision Matrix
| Factor | Vite SPA | Next.js | Remix | Astro |
|--------|----------|---------|-------|-------|
| SEO needed | ❌ | ✅ Best | ✅ Good | ✅ Best |
| Dashboard/app | ✅ Best | ✅ Good | ✅ Good | ❌ |
| Content-heavy | ❌ | ✅ Good | ✅ Good | ✅ Best |
| Team familiarity | ✅ Simple | ⚠️ Learning curve | ⚠️ Web standards | ⚠️ Islands |
| Deployment | Anywhere | Vercel optimal | Anywhere | Anywhere |
| Bundle size | You control | Framework overhead | Smaller | Minimal JS |
**Decision rules:**
1. Dashboard/internal tool with no SEO → Vite SPA
2. Marketing + app hybrid → Next.js
3. Content-first with some interactivity → Astro
4. Web-standards-first, nested layouts → Remix
5. Default for most SaaS products → Next.js
---
## Phase 2: Project Structure & Conventions
### Recommended Feature-Based Structure
```
src/
├── app/ # Routes/pages (framework-specific)
├── features/ # Feature modules (THE core pattern)
│ ├── auth/
│ │ ├── components/ # Feature-specific components
│ │ ├── hooks/ # Feature-specific hooks
│ │ ├── api/ # API calls & types
│ │ ├── utils/ # Feature utilities
│ │ ├── types.ts # Feature types
│ │ └── index.ts # Public API (barrel export)
│ ├── dashboard/
│ └── settings/
├── shared/ # Cross-feature shared code
│ ├── components/ # Generic UI components
│ │ ├── ui/ # Primitives (Button, Input, Card)
│ │ └── layout/ # Layout components
│ ├── hooks/ # Generic hooks
│ ├── lib/ # Utilities, constants
│ └── types/ # Global types
├── providers/ # Context providers
└── styles/ # Global styles
```
### 7 Structure Rules
1. **Feature isolation** — features/ never import from other features directly; use shared/ or events
2. **Barrel exports** — every feature has index.ts that defines its public API
3. **Colocation** — tests, stories, and styles live next to their component
4. **Max file size** — 300 lines. If bigger, split
5. **Max component size** — 50 lines of JSX. If bigger, extract
6. **No circular deps** — enforce with eslint-plugin-import
7. **Types colocated** — feature types in feature, shared types in shared/types
### Naming Conventions
```
Components: PascalCase.tsx (UserProfile.tsx)
Hooks: useCamelCase.ts (useAuth.ts)
Utilities: camelCase.ts (formatCurrency.ts)
Types: PascalCase.ts (User.ts) or types.ts
Constants: SCREAMING_SNAKE.ts (API_ENDPOINTS.ts)
Test files: *.test.tsx (UserProfile.test.tsx)
Story files: *.stories.tsx (Button.stories.tsx)
```
---
## Phase 3: Component Design Patterns
### Component Anatomy Template
```tsx
// 1. Imports (grouped: react → third-party → internal → types → styles)
import { useState, useCallback, memo } from 'react'
import { clsx } from 'clsx'
import { Button } from '@/shared/components/ui'
import type { User } from '../types'
// 2. Types (exported for reuse)
export interface UserCardProps {
user: User
onEdit?: (id: string) => void
variant?: 'compact' | 'full'
className?: string
}
// 3. Component (named export, not default)
export const UserCard = memo(function UserCard({
user,
onEdit,
variant = 'full',
className,
}: UserCardProps) {
// 4. Hooks first
const [isExpanded, setIsExpanded] = useState(false)
// 5. Derived state (no useEffect for derived!)
const displayName = `${user.firstName} ${user.lastName}`
// 6. Handlers (useCallback for passed-down refs)
const handleEdit = useCallback(() => {
onEdit?.(user.id)
}, [onEdit, user.id])
// 7. Early returns for edge cases
if (!user) return null
// 8. JSX (max 50 lines)
return (
<div className={clsx('rounded-lg border p-4', className)}>
<h3>{displayName}</h3>
{variant === 'full' && <p>{user.bio}</p>}
{onEdit && <Button onClick={handleEdit}>Edit</Button>}
</div>
)
})
```
### Component Composition Patterns
**1. Compound Components (for related UI groups)**
```tsx
// Usage: <Tabs><Tabs.List><Tabs.Tab>A</Tabs.Tab></Tabs.List><Tabs.Panel>...</Tabs.Panel></Tabs>
const TabsContext = createContext<TabsContextType | null>(null)
export function Tabs({ children, defaultValue }: TabsProps) {
const [activeTab, setActiveTab] = useState(defaultValue)
return (
<TabsContext.Provider value={{ activeTab, setActiveTab }}>
{children}
</TabsContext.Provider>
)
}
Tabs.List = TabsList
Tabs.Tab = TabsTab
Tabs.Panel = TabsPanel
```
**2. Render Props (for flexible rendering logic)**
```tsx
export function DataList<T>({ items, renderItem, renderEmpty }: DataListProps<T>) {
if (items.length === 0) return renderEmpty?.() ?? <EmptyState />
return <ul>{items.map((item, i) => <li key={i}>{renderItem(item)}</li>)}</ul>
}
```
**3. Higher-Order Components (for cross-cutting concerns — use sparingly)**
```tsx
export function withAuth<P>(Component: ComponentType<P>) {
return function AuthenticatedComponent(props: P) {
const { user, isLoading } = useAuth()
if (isLoading) return <Spinner />
if (!user) return <Navigate to="/login" />
return <Component {...props} />
}
}
```
### 10 Component Rules
1. **One component per file** — always
2. **Named exports** — never default exports (refactoring safety)
3. **Props interface** — always explicit, always exported
4. **No business logic in components** — extract to hooks
5. **No inline styles** — use Tailwind classes or CSS modules
6. **No string refs** — useRef only
7. **No index as key** — use stable identifiers
8. **Memo strategically** — not everywhere, only for expensive renders
9. **Children over props** — prefer composition over configuration
10. **Accessible by default** — semantic HTML, ARIA when needed
---
## Phase 4: State Management Decision Framework
### State Type Decision Tree
```
Is it server data (from API)?
├─ YES → TanStack Query (or SWR) — NEVER Redux/Zustand for server state
│
└─ NO → Is it shared across features?
├─ YES → Is it complex with many actions?
│ ├─ YES → Zustand (or Redux Toolkit if team knows it)
│ └─ NO → Jotai (atomic) or Zustand (simple store)
│
└─ NO → Is it shared within a feature?
├─ YES → Context + useReducer (or Zustand feature store)
└─ NO → useState / useReducer (component-local)
```
### State Management Comparison
| Tool | Best For | Bundle | Learning | Team Size |
|------|----------|--------|----------|----