6.4 KiB
6.4 KiB
组件创建规范
目录结构
采用模块化结构组织组件:
src/components/
├── video/
│ ├── index.ts # 导出入口
│ ├── video.tsx # 主组件
│ ├── video.types.ts # 类型定义
│ ├── video.hooks.ts # 组件专用 hooks(可选)
│ └── video.utils.ts # 工具函数(可选)
├── button/
│ ├── index.ts
│ └── button.tsx
├── ui/ # 基础 UI 组件
│ ├── button.tsx
│ └── dialog.tsx
└── index.ts # 统一导出所有组件
命名规范
| 类型 | 规范 | 示例 |
|---|---|---|
| 文件名 | kebab-case | video-player.tsx |
| 目录名 | kebab-case | video-player/ |
| 组件名 | PascalCase | VideoPlayer |
| Props 接口 | {组件名}Props |
VideoPlayerProps |
| Ref 接口 | {组件名}Ref |
VideoPlayerRef |
| 导出类型 | {组件名}{类型名} |
VideoAnchor |
文件结构顺序
每个组件文件按以下顺序组织:
- Imports - 导入语句
- Types/Interfaces - 类型定义(需导出)
- Constants - 常量定义
- Helper Functions - 辅助函数
- Component - 组件定义
- displayName - 设置显示名称
- Export - 默认导出
组件模板
import React, {
forwardRef,
useRef,
useState,
useImperativeHandle,
} from "react";
import { cn } from "@/lib/utils";
/** 组件配置项 */
export interface ComponentNameProps {
/** 必填属性说明 */
requiredProp: string;
/** 可选属性说明 */
optionalProp?: boolean;
/** 子元素 */
children?: React.ReactNode;
/** 自定义类名 */
className?: string;
}
/** 组件 Ref 暴露的方法 */
export interface ComponentNameRef {
/** 方法说明 */
methodName: () => void;
}
/**
* ComponentName - 组件简要说明
*
* @example
* ```tsx
* <ComponentName requiredProp="value" />
* ```
*/
const ComponentName = forwardRef<ComponentNameRef, ComponentNameProps>(
({ requiredProp, optionalProp = false, className, children }, ref) => {
// 状态定义
const [state, setState] = useState<string>("");
// Ref 定义
const innerRef = useRef<HTMLDivElement>(null);
// 暴露方法给父组件
useImperativeHandle(ref, () => ({
methodName: () => {
// 实现
},
}));
return <div className={cn("base-class", className)}>{children}</div>;
}
);
ComponentName.displayName = "ComponentName";
export default ComponentName;
index.ts 导出模板
export { default } from "./component-name";
export { default as ComponentName } from "./component-name";
export type { ComponentNameProps, ComponentNameRef } from "./component-name";
类型规范
- 必须为所有 props、state、函数参数和返回值声明类型
- 禁止使用
any,使用unknown或泛型替代 - 导出所有公共接口和类型
- 使用
React.ReactNode表示子元素类型 - 使用
React.CSSProperties表示样式对象
样式规范
- 使用
cn()工具函数合并类名 - 优先使用 Tailwind CSS 类名
- 支持通过
classNameprop 自定义样式 - 避免内联样式,除非是动态计算值
// ✅ 推荐
<div className={cn("flex items-center", isActive && "bg-blue-500", className)}>
// ❌ 避免
<div style={{ display: "flex", alignItems: "center" }}>
最佳实践
- 单一职责 - 每个组件只做一件事,保持在 200 行以内
- 使用 forwardRef - 需要暴露 ref 的组件必须使用
- 设置 displayName - 便于 React DevTools 调试
- 提取逻辑 - 复杂逻辑提取到自定义 hooks
- 组合优于继承 - 使用 children 和 render props
- 早返回 - 避免深层嵌套,使用 early return
文件拆分指南
| 文件 | 用途 | 何时创建 |
|---|---|---|
*.tsx |
主组件 | 必须 |
*.types.ts |
类型定义 | 类型超过 30 行 |
*.hooks.ts |
组件专用 hooks | 有可复用的状态逻辑 |
*.utils.ts |
工具函数 | 有纯函数逻辑需要提取 |
*.constants.ts |
常量定义 | 有多个常量需要共享 |