React Production Engineering

TotalClaw 作者 1kalin v1.0.0

通过架构决策、组件设计、状态管理、性能优化、测试和部署构建生产级 React 应用程序的完整方法。

源码 ↗

安装 / 下载方式

TotalClaw CLI推荐
totalclaw install totalclaw:1kalin~afrexai-react-production
cURL直接下载,无需登录
curl -fsSL https://skills.taituai.com/api/skills/totalclaw%3A1kalin~afrexai-react-production/file -o afrexai-react-production.md
Git 仓库获取源码
git clone https://github.com/openclaw/skills/commit/8f51b22d8d64574d7f4975065b3b07678069cfa1
## 概述(中文)

通过架构决策、组件设计、状态管理、性能优化、测试和部署构建生产级 React 应用程序的完整方法。

## 原文

# 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