Files
shanghai-residences/src/components/COMPONENT_GUIDELINES.md
T

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

文件结构顺序

每个组件文件按以下顺序组织:

  1. Imports - 导入语句
  2. Types/Interfaces - 类型定义(需导出)
  3. Constants - 常量定义
  4. Helper Functions - 辅助函数
  5. Component - 组件定义
  6. displayName - 设置显示名称
  7. 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 类名
  • 支持通过 className prop 自定义样式
  • 避免内联样式,除非是动态计算值
// ✅ 推荐
<div className={cn("flex items-center", isActive && "bg-blue-500", className)}>

// ❌ 避免
<div style={{ display: "flex", alignItems: "center" }}>

最佳实践

  1. 单一职责 - 每个组件只做一件事,保持在 200 行以内
  2. 使用 forwardRef - 需要暴露 ref 的组件必须使用
  3. 设置 displayName - 便于 React DevTools 调试
  4. 提取逻辑 - 复杂逻辑提取到自定义 hooks
  5. 组合优于继承 - 使用 children 和 render props
  6. 早返回 - 避免深层嵌套,使用 early return

文件拆分指南

文件 用途 何时创建
*.tsx 主组件 必须
*.types.ts 类型定义 类型超过 30 行
*.hooks.ts 组件专用 hooks 有可复用的状态逻辑
*.utils.ts 工具函数 有纯函数逻辑需要提取
*.constants.ts 常量定义 有多个常量需要共享