generic-react-feature-developer

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

React Feature Developer

React功能开发指南

Guide feature development with React architecture patterns.
Extends: Generic Feature Developer - Read base skill for development workflow, scope assessment, and build vs integrate decisions.
基于React架构模式的功能开发指导。
扩展自: 通用功能开发者 - 阅读基础技能文档以了解开发工作流、范围评估以及自研与集成的决策方法。

React Architecture

React架构

Project Structure

项目结构

src/
├── components/
│   ├── ui/          # Reusable primitives (Button, Input)
│   ├── features/    # Feature-specific components
│   └── layout/      # Layout components (Header, Sidebar)
├── hooks/           # Custom hooks (useAuth, useStore)
├── stores/          # Zustand stores
├── services/        # API clients, IndexedDB wrappers
├── types/           # TypeScript interfaces
└── lib/             # Utilities
src/
├── components/
│   ├── ui/          # 可复用基础组件(Button、Input)
│   ├── features/    # 功能专属组件
│   └── layout/      # 布局组件(Header、Sidebar)
├── hooks/           # 自定义hooks(useAuth、useStore)
├── stores/          # Zustand状态仓库
├── services/        # API客户端、IndexedDB封装
├── types/           # TypeScript接口
└── lib/             # 工具函数

State Management Patterns

状态管理模式

Zustand Store (Preferred)

Zustand仓库(推荐)

typescript
// stores/useFeatureStore.ts
interface FeatureState {
  items: Item[];
  isLoading: boolean;
  // Actions
  addItem: (item: Item) => void;
  removeItem: (id: string) => void;
}

const useFeatureStore = create<FeatureState>()(
  persist(
    (set) => ({
      items: [],
      isLoading: false,
      addItem: (item) => set((s) => ({ items: [...s.items, item] })),
      removeItem: (id) =>
        set((s) => ({
          items: s.items.filter((i) => i.id !== id),
        })),
    }),
    {
      name: "feature-storage",
      version: 1,
      migrate: (state, version) => {
        // Handle migrations between versions
        return state as FeatureState;
      },
    },
  ),
);
typescript
// stores/useFeatureStore.ts
interface FeatureState {
  items: Item[];
  isLoading: boolean;
  // Actions
  addItem: (item: Item) => void;
  removeItem: (id: string) => void;
}

const useFeatureStore = create<FeatureState>()(
  persist(
    (set) => ({
      items: [],
      isLoading: false,
      addItem: (item) => set((s) => ({ items: [...s.items, item] })),
      removeItem: (id) =>
        set((s) => ({
          items: s.items.filter((i) => i.id !== id),
        })),
    }),
    {
      name: "feature-storage",
      version: 1,
      migrate: (state, version) => {
        // 处理版本间的迁移
        return state as FeatureState;
      },
    },
  ),
);

Zustand Selectors (Performance)

Zustand选择器(性能优化)

typescript
// Avoid re-renders with selectors
const items = useFeatureStore((state) => state.items);
const addItem = useFeatureStore((state) => state.addItem);

// Shallow compare for objects
import { shallow } from "zustand/shallow";
const { items, isLoading } = useFeatureStore(
  (state) => ({ items: state.items, isLoading: state.isLoading }),
  shallow,
);
typescript
// 使用选择器避免不必要重渲染
const items = useFeatureStore((state) => state.items);
const addItem = useFeatureStore((state) => state.addItem);

// 对对象进行浅比较
import { shallow } from "zustand/shallow";
const { items, isLoading } = useFeatureStore(
  (state) => ({ items: state.items, isLoading: state.isLoading }),
  shallow,
);

Context vs Zustand Decision

Context与Zustand的选择决策

Use ContextUse Zustand
Theme, locale (rarely changes)Frequently updated data
Authentication stateComplex state with actions
Provider already existsNeed persistence
Prop drilling 1-2 levelsCross-cutting concern
使用Context的场景使用Zustand的场景
主题、语言环境(极少变更)频繁更新的数据
认证状态包含复杂操作的状态
已存在Provider需要持久化的状态
1-2层级的属性透传跨组件的关注点

Server State (React Query)

服务端状态(React Query)

typescript
// Server state - React Query
const { data, isLoading, error } = useQuery({
  queryKey: ["items", userId],
  queryFn: () => fetchItems(userId),
  staleTime: 5 * 60 * 1000, // 5 minutes
});

// Mutations
const mutation = useMutation({
  mutationFn: createItem,
  onSuccess: () => {
    queryClient.invalidateQueries({ queryKey: ["items"] });
  },
});
typescript
// 服务端状态 - React Query
const { data, isLoading, error } = useQuery({
  queryKey: ["items", userId],
  queryFn: () => fetchItems(userId),
  staleTime: 5 * 60 * 1000, // 5分钟
});

// 变更操作
const mutation = useMutation({
  mutationFn: createItem,
  onSuccess: () => {
    queryClient.invalidateQueries({ queryKey: ["items"] });
  },
});

IndexedDB Integration

IndexedDB集成

When to Use

适用场景

ScenarioSolution
< 5MB totallocalStorage via Zustand persist
> 5MB totalIndexedDB
Binary data (images, files)IndexedDB
Simple key-valuelocalStorage
Complex queriesIndexedDB
场景解决方案
总数据量 < 5MB通过Zustand persist使用localStorage
总数据量 > 5MBIndexedDB
二进制数据(图片、文件)IndexedDB
简单键值对存储localStorage
复杂查询需求IndexedDB

Service Wrapper Pattern

服务封装模式

typescript
// services/indexedDBService.ts
class IndexedDBService {
  private db: IDBDatabase | null = null;

  async init() {
    return new Promise<void>((resolve, reject) => {
      const request = indexedDB.open("AppDB", 1);
      request.onerror = () => reject(request.error);
      request.onsuccess = () => {
        this.db = request.result;
        resolve();
      };
      request.onupgradeneeded = (event) => {
        const db = (event.target as IDBOpenDBRequest).result;
        db.createObjectStore("items", { keyPath: "id" });
      };
    });
  }

  async setItem<T>(store: string, value: T): Promise<void> {
    // Implementation
  }

  async getItem<T>(store: string, key: string): Promise<T | null> {
    // Implementation
  }
}

export const indexedDBService = new IndexedDBService();
typescript
// services/indexedDBService.ts
class IndexedDBService {
  private db: IDBDatabase | null = null;

  async init() {
    return new Promise<void>((resolve, reject) => {
      const request = indexedDB.open("AppDB", 1);
      request.onerror = () => reject(request.error);
      request.onsuccess = () => {
        this.db = request.result;
        resolve();
      };
      request.onupgradeneeded = (event) => {
        const db = (event.target as IDBOpenDBRequest).result;
        db.createObjectStore("items", { keyPath: "id" });
      };
    });
  }

  async setItem<T>(store: string, value: T): Promise<void> {
    // 实现代码
  }

  async getItem<T>(store: string, key: string): Promise<T | null> {
    // 实现代码
  }
}

export const indexedDBService = new IndexedDBService();

Lazy Loading

懒加载

Component Lazy Loading

组件懒加载

typescript
// Heavy components (>20KB)
const HeavyChart = lazy(() => import('./HeavyChart'));
const RichTextEditor = lazy(() => import('./RichTextEditor'));

// Pages
const SettingsPage = lazy(() => import('./pages/Settings'));

// Usage with Suspense
<Suspense fallback={<Skeleton />}>
  <HeavyChart data={data} />
</Suspense>
typescript
// 大型组件(>20KB)
const HeavyChart = lazy(() => import('./HeavyChart'));
const RichTextEditor = lazy(() => import('./RichTextEditor'));

// 页面组件
const SettingsPage = lazy(() => import('./pages/Settings'));

// 结合Suspense使用
<Suspense fallback={<Skeleton />}>
  <HeavyChart data={data} />
</Suspense>

Route-Level Code Splitting

路由级代码分割

typescript
// React Router example
const routes = [
  {
    path: '/dashboard',
    element: <DashboardLayout />,
    children: [
      {
        path: 'settings',
        lazy: () => import('./pages/Settings'),
      },
    ],
  },
];
typescript
// React Router示例
const routes = [
  {
    path: '/dashboard',
    element: <DashboardLayout />,
    children: [
      {
        path: 'settings',
        lazy: () => import('./pages/Settings'),
      },
    ],
  },
];

Custom Hook Patterns

自定义Hook模式

Feature Hook

功能专属Hook

typescript
// hooks/useItems.ts
function useItems() {
  const items = useFeatureStore((s) => s.items);
  const addItem = useFeatureStore((s) => s.addItem);

  const sortedItems = useMemo(
    () => [...items].sort((a, b) => b.createdAt - a.createdAt),
    [items],
  );

  return { items: sortedItems, addItem };
}
typescript
// hooks/useItems.ts
function useItems() {
  const items = useFeatureStore((s) => s.items);
  const addItem = useFeatureStore((s) => s.addItem);

  const sortedItems = useMemo(
    () => [...items].sort((a, b) => b.createdAt - a.createdAt),
    [items],
  );

  return { items: sortedItems, addItem };
}

Compound Hook (Combining Sources)

复合Hook(组合多数据源)

typescript
// hooks/useDashboard.ts
function useDashboard() {
  // Local state
  const [filter, setFilter] = useState("all");

  // Server state
  const { data: items } = useQuery({ queryKey: ["items"] });

  // Client state
  const preferences = usePreferencesStore((s) => s.dashboard);

  // Derived
  const filteredItems = useMemo(
    () => items?.filter((i) => filter === "all" || i.status === filter),
    [items, filter],
  );

  return { filter, setFilter, items: filteredItems, preferences };
}
typescript
// hooks/useDashboard.ts
function useDashboard() {
  // 本地状态
  const [filter, setFilter] = useState("all");

  // 服务端状态
  const { data: items } = useQuery({ queryKey: ["items"] });

  // 客户端状态
  const preferences = usePreferencesStore((s) => s.dashboard);

  // 派生数据
  const filteredItems = useMemo(
    () => items?.filter((i) => filter === "all" || i.status === filter),
    [items, filter],
  );

  return { filter, setFilter, items: filteredItems, preferences };
}

Component Composition

组件组合

Compound Components

复合组件

tsx
// Usage: <Tabs><Tabs.List /><Tabs.Panel /></Tabs>
const TabsContext = createContext<TabsContextValue | null>(null);

function Tabs({ children, defaultValue }: TabsProps) {
  const [active, setActive] = useState(defaultValue);
  return (
    <TabsContext.Provider value={{ active, setActive }}>
      {children}
    </TabsContext.Provider>
  );
}

Tabs.List = function TabsList({ children }: { children: ReactNode }) {
  return <div role="tablist">{children}</div>;
};

Tabs.Panel = function TabsPanel({ value, children }: TabsPanelProps) {
  const { active } = useContext(TabsContext)!;
  if (value !== active) return null;
  return <div role="tabpanel">{children}</div>;
};
tsx
// 使用方式: <Tabs><Tabs.List /><Tabs.Panel /></Tabs>
const TabsContext = createContext<TabsContextValue | null>(null);

function Tabs({ children, defaultValue }: TabsProps) {
  const [active, setActive] = useState(defaultValue);
  return (
    <TabsContext.Provider value={{ active, setActive }}>
      {children}
    </TabsContext.Provider>
  );
}

Tabs.List = function TabsList({ children }: { children: ReactNode }) {
  return <div role="tablist">{children}</div>;
};

Tabs.Panel = function TabsPanel({ value, children }: TabsPanelProps) {
  const { active } = useContext(TabsContext)!;
  if (value !== active) return null;
  return <div role="tabpanel">{children}</div>;
};

React Feature Checklist

React功能开发检查清单

Before Starting:
  • Read CLAUDE.md for project patterns
  • Check existing components for reuse
  • Plan state management approach
  • Estimate bundle size impact
During Development:
  • Follow project design system
  • TypeScript strict mode
  • Implement keyboard navigation
  • Add ARIA labels
  • Support dark mode
Before Completion:
  • Write unit tests
  • Lazy load heavy components
  • Check bundle size:
    npm run build
  • Review with code-reviewer skill
开始开发前:
  • 阅读CLAUDE.md了解项目模式
  • 检查现有组件是否可复用
  • 规划状态管理方案
  • 评估对包体积的影响
开发过程中:
  • 遵循项目设计系统规范
  • 启用TypeScript严格模式
  • 实现键盘导航支持
  • 添加ARIA标签
  • 支持深色模式
完成前:
  • 编写单元测试
  • 对大型组件进行懒加载
  • 检查包体积:
    npm run build
  • 使用代码评审技能进行代码审查

See Also

相关链接

  • Generic Feature Developer - Workflow, decisions
  • Code Review Standards - Quality requirements
  • Design Patterns - UI patterns
  • 通用功能开发者 - 工作流与决策方法
  • 代码评审标准 - 质量要求
  • 设计模式 - UI模式