一、基础规范
1.1 文件命名
// ✅ 推荐
user-profile.tsx
shopping-cart-service.ts
order-utils.ts
constants.ts
// ❌ 避免
UserProfile.tsx // PascalCase只用于组件
userProfile.ts // 混用命名风格
1.2 目录结构
src/
├── components/ # 通用组件
│ ├── common/ # 全平台通用
│ └── business/ # 业务组件
├── pages/ # 页面组件
├── services/ # API服务层
├── hooks/ # 自定义hooks
├── utils/ # 工具函数
├── constants/ # 常量定义
├── types/ # TypeScript类型
└── styles/ # 样式文件
二、React/TypeScript规范
2.1 组件设计
// ✅ 函数式组件 + TypeScript
interface ProductCardProps {
productId: string;
title: string;
price: number;
onAddToCart?: (id: string) => void;
}
const ProductCard: React.FC<ProductCardProps> = ({
productId,
title,
price,
onAddToCart
}) => {
const [isLoading, setIsLoading] = useState(false);
const handleClick = useCallback(async () => {
setIsLoading(true);
try {
await onAddToCart?.(productId);
} finally {
setIsLoading(false);
}
}, [productId, onAddToCart]);
return (
<div className="product-card">
<h3>{title}</h3>
<p>¥{price.toFixed(2)}</p>
<button
onClick={handleClick}
disabled={isLoading}
aria-label={`添加${title}到购物车`}
>
{isLoading ? '添加中...' : '加入购物车'}
</button>
</div>
);
};
// 添加displayName便于调试
ProductCard.displayName = 'ProductCard';
2.2 Hooks使用规范
// ✅ 自定义hook
const useProductDetail = (productId: string) => {
const [product, setProduct] = useState<Product | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
let mounted = true;
const fetchProduct = async () => {
try {
const data = await productService.getDetail(productId);
if (mounted) {
setProduct(data);
}
} catch (error) {
console.error('Failed to fetch product:', error);
} finally {
if (mounted) {
setLoading(false);
}
}
};
fetchProduct();
return () => {
mounted = false;
};
}, [productId]);
return { product, loading };
};
// ❌ 避免在循环/条件中使用hooks
if (condition) {
const [state, setState] = useState(); // 错误!
}
三、样式规范
3.1 CSS Modules(推荐)
/* ProductCard.module.css */
.productCard {
border: 1px solid var(--border-color);
border-radius: 8px;
padding: 16px;
}
.title {
font-size: 16px;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 8px;
}
.price {
color: var(--price-color);
font-size: 20px;
font-weight: bold;
}
3.2 CSS-in-JS规范
import styled from '@emotion/styled';
const StyledButton = styled.button<{ $primary?: boolean }>`
padding: 12px 24px;
border-radius: 4px;
border: none;
background-color: ${props =>
props.$primary ? 'var(--primary-color)' : 'var(--secondary-color)'};
color: white;
font-size: 14px;
cursor: pointer;
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
&:hover:not(:disabled) {
opacity: 0.9;
}
`;
四、性能优化
4.1 代码分割
// 动态导入
const ProductList = lazy(() => import('./ProductList'));
// React.lazy + Suspense
<Suspense fallback={<LoadingSpinner />}>
<ProductList />
</Suspense>
4.2 内存优化
// ✅ 使用useCallback避免重复创建函数
const handleSubmit = useCallback((values: FormValues) => {
submitOrder(values);
}, []);
// ✅ 使用useMemo缓存计算结果
const filteredProducts = useMemo(() => {
return products.filter(p =>
p.price >= minPrice && p.price <= maxPrice
);
}, [products, minPrice, maxPrice]);
五、错误处理
5.1 API错误处理
class ApiService {
private async request<T>(
endpoint: string,
options?: RequestInit
): Promise<T> {
try {
const response = await fetch(`${API_BASE}${endpoint}`, {
...options,
headers: {
'Content-Type': 'application/json',
...options?.headers,
},
});
if (!response.ok) {
throw new HttpError(response.status, await response.text());
}
return await response.json();
} catch (error) {
if (error instanceof HttpError) {
// 处理HTTP错误
Sentry.captureException(error);
}
throw error;
}
}
}
5.2 React错误边界
class ErrorBoundary extends React.Component<
{ children: ReactNode; fallback?: ReactNode },
{ hasError: boolean }
> {
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
// 上报错误
errorReporter.log({
error,
errorInfo,
timestamp: Date.now(),
});
}
render() {
if (this.state.hasError) {
return this.props.fallback || <DefaultErrorPage />;
}
return this.props.children;
}
}
六、代码质量
6.1 ESLint配置
{
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended"
],
"rules": {
"@typescript-eslint/explicit-function-return-type": "warn",
"@typescript-eslint/no-explicit-any": "error",
"react/prop-types": "off",
"no-console": ["warn", { "allow": ["warn", "error"] }]
}
}
6.2 Git提交规范
feat: 新增商品详情页骨架屏
fix: 修复购物车价格计算错误
perf: 优化首屏加载速度
docs: 更新README使用说明
style: 调整按钮hover样式
refactor: 重构订单状态管理
test: 添加购物车单元测试
chore: 更新依赖版本
七、测试规范
7.1 单元测试
// __tests__/utils/priceFormatter.test.ts
describe('priceFormatter', () => {
it('应该正确格式化价格', () => {
expect(formatPrice(1999)).toBe('¥1,999.00');
expect(formatPrice(0)).toBe('¥0.00');
});
it('应该处理负数和NaN', () => {
expect(formatPrice(-100)).toBe('-¥100.00');
expect(formatPrice(NaN)).toBe('¥0.00');
});
});
7.2 组件测试
// __tests__/components/AddToCartButton.test.tsx
describe('AddToCartButton', () => {
it('点击时应该调用onClick回调', async () => {
const mockOnClick = jest.fn();
const { getByRole } = render(
<AddToCartButton productId="123" onClick={mockOnClick} />
);
const button = getByRole('button');
await userEvent.click(button);
expect(mockOnClick).toHaveBeenCalledWith('123');
});
});
八、监控与日志
8.1 性能监控
// 关键性能指标
const reportWebVitals = (metric: any) => {
analytics.send({
type: 'performance',
name: metric.name,
value: metric.value,
timestamp: Date.now(),
});
};
// 用户行为追踪
const trackUserAction = (action: string, data?: Record<string, any>) => {
if (process.env.NODE_ENV === 'production') {
userBehaviorTracker.log({
action,
data,
page: window.location.pathname,
timestamp: new Date().toISOString(),
});
}
};
总结要点
类型安全优先:全面使用TypeScript,避免any类型
组件职责单一:每个组件只关注一个功能点
性能意识:合理使用memoization、代码分割
错误可追溯:完善的错误处理和日志记录
代码可测试:编写易于测试的纯函数和组件
保持一致性:团队统一的命名、结构和规范
渐进式优化:先实现功能正确性,再逐步优化
快手电商场景特别需要注意:
- 高并发下的性能表现
- 移动端兼容性
- 电商特有的无障碍访问
- 数据敏感性和安全性
- 快速迭代中的代码可维护性
建议配合Prettier、Husky、Commitlint等工具自动化检查,确保规范落地执行。