# 最佳实践 > **文档版本**: v1.0.0 > **创建日期**: 2026-05-25 > **适用范围**: FischerX 项目开发人员 ## 目录 - [前端最佳实践](#前端最佳实践) - [后端最佳实践](#后端最佳实践) - [共享包开发](#共享包开发) - [测试最佳实践](#测试最佳实践) --- ## 前端最佳实践 ### 组件设计 #### 单一职责原则 每个组件应该只做一件事,保持组件保持组件应该组件应该只做一件事 ```tsx // 好的做法 function UserList({ users }: { users: User[] }) { return ( <div className="user-list"> {users.map(user => ( <UserCard key={user.id} user={user} /> ))} </div> ); } function UserCard({ user }: { user: User }) { return ( <div className="user-card"> <UserAvatar user={user} /> <UserInfo user={user} /> </div> ); } // 避免 - 组件太大太组件太组件太大了 function UserPage({ users }: { users: User[] }) { return ( <div className="user-page"> {users.map(user => ( <div key={user.id} className="user-card"> <img src={user.avatar} alt={user.name} /> <div> <h3>{user.name}</h3> <p>{user.email}</p> </div> </div> ))} </div> ); } ``` #### Props 解构与组合 使用组合而不是继承,使用组合而不是继承 ```tsx // 好的做法 function Button({ children, variant = 'primary', className, ...props }: ButtonProps) { return ( <button className={cn(buttonVariants({ variant }), className)} {...props} > {children} </button> ); } // 使用 <Button variant="secondary" onClick={handleClick} disabled={isLoading}> <Icon /> Submit </Button> ``` ### 状态管理 #### 使用 React Query 进行服务器状态 ```tsx // hooks/useUsers.ts import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { userApi } from '@/lib/api'; export function useUsers() { return useQuery({ queryKey: ['users'], queryFn: userApi.getAll, }); } export function useCreateUser() { const queryClient = useQueryClient(); return useMutation({ mutationFn: userApi.create, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['users'] }); }, }); } ``` #### 使用 Zustand 进行客户端状态 ```tsx // stores/useAuthStore.ts import { create } from 'zustand'; import { persist } from 'zustand/middleware'; interface AuthState { user: User | null; token: string | null; setUser: (user: User | null) => void; setToken: (token: string | null) => void; logout: () => void; } export const useAuthStore = create<AuthState>()( persist( (set) => ({ user: null, token: null, setUser: (user) => set({ user }), setToken: (token) => set({ token }), logout: () => set({ user: null, token: null }), }), { name: 'auth-storage', } ) ); ``` ### 性能优化 #### 组件懒加载 ```tsx // 使用动态导入 const HeavyComponent = dynamic(() => import('./HeavyComponent'), { loading: () => <div>Loading...</div>, ssr: false, }); // 在需要时再加载 function SomePage() { const [showHeavy, setShowHeavy] = useState(false); return ( <div> <button onClick={() => setShowHeavy(true)}>Show</button> {showHeavy && <HeavyComponent />} </div> ); } ``` #### 使用 useMemo 和 useCallback ```tsx // 只在 dependencies 变化时重新计算 const filteredUsers = useMemo(() => { return users.filter(user => user.active); }, [users]); // 只在 dependencies 变化时重新创建函数 const handleUserClick = useCallback((user: User) => { navigate(`/users/${user.id}`); }, [navigate]); ``` --- ## 后端最佳实践 ### API 设计 #### RESTful 规范 ```typescript // 好的做法 GET /users # 获取用户列表 GET /users/:id # 获取单个用户 POST /users # 创建用户 PUT /users/:id # 更新用户 DELETE /users/:id # 删除用户 GET /users/:id/orders # 获取用户订单 ``` #### 统一响应格式 ```typescript // 成功响应 { "success": true, "data": { ... }, "message": "Operation successful" } // 错误响应 { "success": false, "error": { "code": "NOT_FOUND", "message": "User not found", "details": [] } } ``` ### 数据库设计 #### 使用 Prisma 迁移 ```prisma // schema.prisma model User { id String @id @default(cuid()) name String email String @unique password String role Role @default(USER) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([email]) } enum Role { USER ADMIN } ``` #### 数据库查询优化 ```typescript // 使用 select 只查询需要的字段 async function getUsers() { return this.prisma.user.findMany({ select: { id: true, name: true, email: true, }, }); } // 使用 include 加载关联数据 async function getUserWithOrders(id: string) { return this.prisma.user.findUnique({ where: { id }, include: { orders: true }, }); } ``` ### 缓存策略 ```typescript // 使用 Redis 缓存 @Injectable() export class UserService { constructor( private prisma: PrismaService, @Inject(CACHE_MANAGER) private cacheManager: Cache, ) {} async findOne(id: string) { const cacheKey = `user:${id}`; const cached = await this.cacheManager.get(cacheKey); if (cached) { return cached; } const user = await this.prisma.user.findUnique({ where: { id } }); await this.cacheManager.set(cacheKey, user, 300); // 5 分钟 return user; } } ``` --- ## 共享包开发 ### 包的设计原则 #### 高内聚低耦合 ```typescript // packages/utils/src/string.ts export function formatDate(date: Date): string { return new Intl.DateTimeFormat('zh-CN').format(date); } export function truncate(str: string, length: number): string { return str.length > length ? `${str.slice(0, length)}...` : str; } export function capitalize(str: string): string { return str.charAt(0).toUpperCase() + str.slice(1); } ``` #### 明确的导出 ```typescript // packages/utils/src/index.ts export * from './string'; export * from './date'; export * from './validation'; ``` ### 类型安全 ```typescript // packages/types/src/user.ts export interface User { id: string; name: string; email: string; role: 'admin' | 'user'; } export type CreateUserInput = Omit<User, 'id'>; export type UpdateUserInput = Partial<CreateUserInput>; ``` --- ## 测试最佳实践 ### 单元测试 #### 使用 Vitest 进行前端测试 ```typescript // components/__tests__/UserCard.test.tsx import { describe, it, expect } from 'vitest'; import { render, screen } from '@testing-library/react'; import { UserCard } from '../UserCard'; describe('UserCard', () => { const user = { id: '1', name: 'John Doe', email: 'john@example.com', }; it('renders user information', () => { render(<UserCard user={user} />); expect(screen.getByText('John Doe')).toBeInTheDocument(); expect(screen.getByText('john@example.com')).toBeInTheDocument(); }); }); ``` #### 使用 Jest 进行后端测试 ```typescript // services/api/src/user/user.service.spec.ts import { Test, TestingModule } from '@nestjs/testing'; import { UserService } from './user.service'; describe('UserService', () => { let service: UserService; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ providers: [UserService], }).compile(); service = module.get<UserService>(UserService); }); it('should be defined', () => { expect(service).toBeDefined(); }); }); ``` ### 测试原则 - **AAA 模式**: Arrange, Act, Assert - **描述性的测试名称 - **测试应该独立 - **测试行为而不是实现 ```typescript describe('UserService', () => { it('should create a new user', async () => { // Arrange const createUserDto = { name: 'Test', email: 'test@example.com', password: 'password123', }; // Act const result = await service.create(createUserDto); // Assert expect(result.name).toEqual('Test'); }); }); ``` --- ## 下一步 - [常见问题](./troubleshooting.md) - 查看常见问题 - [贡献指南](./contributing.md) - 了解如何贡献 --- > **文档维护**: 本文档由开发团队维护,如有问题或建议请提交 Issue。 > **最后更新**: 2026-05-25