|
|
@@ -0,0 +1,139 @@
|
|
|
+---
|
|
|
+description: React 应用的编码标准和最佳实践
|
|
|
+---
|
|
|
+
|
|
|
+# React 最佳实践
|
|
|
+
|
|
|
+## 项目结构
|
|
|
+- 所有前端代码位于 `web` 目录
|
|
|
+- 主应用代码位于 `web/apps/labelstudio`
|
|
|
+- 共享库位于 `web/libs`
|
|
|
+- 遵循既定的目录结构:
|
|
|
+ - `components/`: 可复用的 UI 组件
|
|
|
+ - `pages/`: 顶层页面组件
|
|
|
+ - `utils/`: 工具函数
|
|
|
+ - `hooks/`: 自定义 React Hooks
|
|
|
+ - `atoms/`: Jotai 原子状态定义
|
|
|
+ - `providers/`: Context 提供者
|
|
|
+ - `services/`: API 和其他服务
|
|
|
+ - `types/`: TypeScript 类型定义
|
|
|
+ - `assets/`: 静态资源
|
|
|
+
|
|
|
+## 组件结构
|
|
|
+- 使用函数组件而非类组件
|
|
|
+- 保持组件小而专注
|
|
|
+- 将可复用逻辑提取到自定义 Hooks
|
|
|
+- 使用组合而非继承
|
|
|
+- 使用 TypeScript 实现适当的 prop 类型
|
|
|
+- 将大组件拆分为更小、更专注的组件
|
|
|
+- 遵循一致的文件组织模式:
|
|
|
+ ```
|
|
|
+ component-name/
|
|
|
+ component-name.tsx
|
|
|
+ component-name.module.scss
|
|
|
+ component-name.test.tsx
|
|
|
+ index.ts
|
|
|
+ ```
|
|
|
+
|
|
|
+## Hooks 使用
|
|
|
+- 遵循 Hooks 规则(只在顶层调用、只在 React 函数中调用)
|
|
|
+- 使用自定义 Hooks 实现可复用逻辑
|
|
|
+- 保持 Hooks 专注和简单
|
|
|
+- 除非绝对必要,否则避免使用 useEffect
|
|
|
+- 在 useEffect 中使用适当的依赖数组
|
|
|
+- 在 useEffect 中实现清理逻辑
|
|
|
+- 避免嵌套 Hooks
|
|
|
+
|
|
|
+## 状态管理
|
|
|
+- 使用 useState 管理本地组件状态
|
|
|
+- 使用 Jotai 原子而非 Context API 管理共享状态
|
|
|
+- 使用 atomWithReducer 处理复杂状态逻辑
|
|
|
+- 使用 atomWithQuery 处理任何 API 数据请求
|
|
|
+- 将状态保持在尽可能接近使用位置的地方
|
|
|
+- 通过适当的状态管理避免 prop drilling
|
|
|
+- 仅使用 Jotai 作为全局状态管理的单一数据源
|
|
|
+
|
|
|
+## 性能优化
|
|
|
+- 实现适当的记忆化(useMemo, useCallback)
|
|
|
+- 对昂贵的组件使用 React.memo
|
|
|
+- 避免不必要的重渲染
|
|
|
+- 实现适当的懒加载
|
|
|
+- 在列表中使用适当的 key props
|
|
|
+- 分析和优化渲染性能
|
|
|
+- 避免在渲染函数中创建新对象或函数
|
|
|
+
|
|
|
+## 开发工具
|
|
|
+- 使用 Biome 进行代码检查和格式化
|
|
|
+- 遵循 .stylelintrc.json 中定义的 CSS/SCSS 检查规则
|
|
|
+- 使用 TypeScript 确保类型安全
|
|
|
+- 通过监控导入来控制打包大小
|
|
|
+
|
|
|
+## 表单处理
|
|
|
+- 对表单输入使用受控组件
|
|
|
+- 实现适当的表单验证
|
|
|
+- 正确处理表单提交状态
|
|
|
+- 显示适当的加载和错误状态
|
|
|
+- 对复杂表单使用表单库
|
|
|
+- 为表单实现适当的无障碍功能
|
|
|
+
|
|
|
+## 错误处理
|
|
|
+- 实现错误边界
|
|
|
+- 正确处理异步错误
|
|
|
+- 显示用户友好的错误消息
|
|
|
+- 实现适当的后备 UI
|
|
|
+- 适当记录错误
|
|
|
+- 优雅处理边缘情况
|
|
|
+
|
|
|
+## 测试
|
|
|
+- 为组件编写单元测试
|
|
|
+- 为复杂流程实现集成测试
|
|
|
+- 使用 React Testing Library
|
|
|
+- 测试用户交互
|
|
|
+- 测试错误场景
|
|
|
+- 实现适当的模拟数据
|
|
|
+
|
|
|
+## 无障碍性
|
|
|
+- 确保组件符合 WCAG 2.1 AA 标准
|
|
|
+- 使用语义化 HTML 元素
|
|
|
+- 实现适当的 ARIA 属性
|
|
|
+- 确保键盘导航
|
|
|
+- 使用屏幕阅读器测试
|
|
|
+- 处理焦点管理
|
|
|
+- 为图片提供适当的 alt 文本
|
|
|
+
|
|
|
+## 代码组织
|
|
|
+- 使用适当的文件命名约定,采用 kebab-case,例如 ListItem -> `list-item.tsx`
|
|
|
+- 优先每个文件夹一个组件,但必要时将相关组件分组在一起,确保每个文件只有一个组件
|
|
|
+- 组件文件夹应包含一个 SCSS `.module.scss` 文件,文件名为组件的 kebab-case 形式,例如 ListItem -> `list-item.module.scss`
|
|
|
+- 实现适当的目录结构
|
|
|
+- UI 组件位于 `web/libs/ui`
|
|
|
+- 跨应用共享的应用组件(如某些页面级块)位于 `web/libs/app-common`
|
|
|
+- `web/apps` 中的代码只能从 `web/libs` 导入,`web/libs` 不能从 `web/apps` 导入
|
|
|
+- `web/libs/app-common` 中的代码只能从其他 `web/libs` 或 `web/apps` 导入。其他 `web/libs` 不能从 `web/libs/app-common` 导入
|
|
|
+- 将原子保存在全局 atoms 文件夹中,文件名与实体或状态意图匹配
|
|
|
+- 通过将 story 文件与组件文件放在一起,将所有组件及其状态添加到 Storybook,例如 `list-item.stories.tsx`
|
|
|
+
|
|
|
+## 包导入规范
|
|
|
+- 使用 `@humansignal/ui` 包获取 UI 组件
|
|
|
+- 使用 `@humansignal/icons` 包获取图标
|
|
|
+- 使用 `@humansignal/core` 包获取核心工具/函数
|
|
|
+- 使用 `@humansignal/app-common` 包获取应用组件
|
|
|
+
|
|
|
+## 最佳实践
|
|
|
+- 禁止循环导入
|
|
|
+- 使用适当的导入/导出
|
|
|
+- 遵循既定的导入顺序
|
|
|
+- 组合组件而非扩展组件
|
|
|
+- 保持组件专注于单一职责
|
|
|
+- 用清晰的注释记录复杂逻辑
|
|
|
+- 遵循项目的文件夹结构和命名约定
|
|
|
+- 优先使用受控组件而非非受控组件
|
|
|
+- 保持组件的纯净性,避免副作用
|
|
|
+- 使用 PropTypes 或 TypeScript 进行类型检查
|
|
|
+
|
|
|
+## 组件设计原则
|
|
|
+- 单一职责原则:每个组件只做一件事
|
|
|
+- 可复用性:设计可在多处使用的组件
|
|
|
+- 可组合性:小组件组合成大组件
|
|
|
+- 可测试性:编写易于测试的组件
|
|
|
+- 可维护性:代码清晰易懂,便于维护
|