generic-react-feature-developer
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseReact 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/ # Utilitiessrc/
├── 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 Context | Use Zustand |
|---|---|
| Theme, locale (rarely changes) | Frequently updated data |
| Authentication state | Complex state with actions |
| Provider already exists | Need persistence |
| Prop drilling 1-2 levels | Cross-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
适用场景
| Scenario | Solution |
|---|---|
| < 5MB total | localStorage via Zustand persist |
| > 5MB total | IndexedDB |
| Binary data (images, files) | IndexedDB |
| Simple key-value | localStorage |
| Complex queries | IndexedDB |
| 场景 | 解决方案 |
|---|---|
| 总数据量 < 5MB | 通过Zustand persist使用localStorage |
| 总数据量 > 5MB | IndexedDB |
| 二进制数据(图片、文件) | 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模式