组件命名规范
组件开发规范和命名规范是前端工程化的重要组成部分,良好的规范和约定能提升代码可读性、可维护性和团队协作效率。从组件设计原则到具体命名规则,需要建立清晰的约束和最佳实践。
组件开发规范
单一职责原则
每个组件应该只关注一个特定功能或UI部分。避免创建多功能巨型组件,当组件超过300行代码时应该考虑拆分。
// 不良实践 - 混合了展示和逻辑
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser(userId).then(setUser);
}, [userId]);
return (
<div className="profile">
<h2>{user?.name}</h2>
<p>{user?.bio}</p>
<button onClick={() => editUser(user)}>Edit</button>
</div>
);
}
// 良好实践 - 分离容器组件和展示组件
function UserProfileContainer({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser(userId).then(setUser);
}, [userId]);
return <UserProfileView user={user} onEdit={editUser} />;
}
function UserProfileView({ user, onEdit }) {
return (
<div className="profile">
<h2>{user?.name}</h2>
<p>{user?.bio}</p>
<button onClick={() => onEdit(user)}>Edit</button>
</div>
);
}
明确的props定义
使用TypeScript或PropTypes明确定义组件接口,包括:
- 必填/选填属性
- 属性类型
- 默认值
- 属性说明
interface ButtonProps {
/**
* 按钮类型
* @default 'primary'
*/
type?: 'primary' | 'secondary' | 'danger';
/**
* 按钮尺寸
*/
size?: 'small' | 'medium' | 'large';
/**
* 点击事件处理函数
*/
onClick?: () => void;
/**
* 是否禁用
*/
disabled?: boolean;
/**
* 按钮文本
*/
children: React.ReactNode;
}
const Button: React.FC<ButtonProps> = ({
type = 'primary',
size = 'medium',
onClick,
disabled = false,
children
}) => {
// 组件实现
};
状态管理规范
- 避免在多个组件中复制相同状态
- 将状态提升到最近的共同祖先组件
- 复杂状态考虑使用Context或状态管理库
- 表单组件应该实现受控组件模式
// 受控组件示例
function SearchInput({ value, onChange }) {
return (
<input
type="text"
value={value}
onChange={(e) => onChange(e.target.value)}
placeholder="Search..."
/>
);
}
// 使用
function SearchPage() {
const [searchTerm, setSearchTerm] = useState('');
return (
<div>
<SearchInput value={searchTerm} onChange={setSearchTerm} />
<SearchResults query={searchTerm} />
</div>
);
}
样式处理方案
- CSS Modules:推荐用于组件级别样式隔离
- CSS-in-JS:适合动态样式需求
- 避免全局样式污染
- 使用设计系统的间距、颜色变量
// Button.module.scss
.button {
padding: 8px 16px;
border-radius: 4px;
font-size: 14px;
&-primary {
background-color: var(--color-primary);
color: white;
}
&-disabled {
opacity: 0.6;
cursor: not-allowed;
}
}
文档和示例
每个组件应该包含:
- 使用示例
- API文档
- 交互说明
- 注意事项
可以使用Storybook或类似工具维护组件文档。
## Button 按钮
常用的操作按钮。
### 基本使用
```jsx
<Button type="primary" onClick={() => alert('Clicked')}>
确认
</Button>
API
属性 | 说明 | 类型 | 默认值 |
---|---|---|---|
type | 按钮类型 | 'primary' | 'secondary' | 'danger' | 'primary' |
size | 按钮尺寸 | 'small' | 'medium' | 'large' | 'medium' |
disabled | 是否禁用 | boolean | false |
## 组件命名规范
### 文件命名
- 使用PascalCase命名组件文件
- 与默认导出组件名保持一致
- 测试文件添加.test后缀
- 样式文件使用模块化命名
components/ Button/ Button.tsx Button.module.scss Button.test.tsx Button.stories.tsx
### 组件命名
- 使用PascalCase命名组件
- 名称应该明确描述组件用途
- 避免通用名称如"Item"、"Component"
- 高阶组件使用"with"前缀
```jsx
// 良好命名
function UserAvatar() {}
function ShoppingCartItem() {}
function withAuth() {}
// 不良命名
function Avatar() {} // 太通用
function Item() {} // 无意义
function auth() {} // 不符合约定
props命名
- 使用camelCase命名props
- 布尔属性应该以is/has/can开头
- 事件处理函数以on开头
- 避免使用DOM属性名如class/for
<Modal
isOpen={true}
onClose={handleClose}
title="Confirm"
showFooter={false}
/>
CSS类名命名
- 使用BEM命名法或类似方案
- 避免使用元素标签选择器
- 前缀与组件名一致
- 状态类使用is-前缀
// BEM示例
.user-card {
&__header {
font-size: 16px;
}
&__avatar {
width: 40px;
&--large {
width: 60px;
}
}
&.is-active {
border-color: blue;
}
}
目录结构规范
按功能或业务域组织组件,避免单一的"components"目录堆积。
src/
components/
ui/ # 通用UI组件
Button/
Input/
Modal/
features/ # 业务功能组件
checkout/
CartItem.tsx
PaymentForm.tsx
layouts/ # 布局组件
MainLayout/
AuthLayout/
测试文件命名
- 测试文件与组件同目录
- 命名模式:ComponentName.test.tsx
- 工具类测试放在__tests__目录
utils/
dateFormatter.ts
__tests__/
dateFormatter.test.ts
类型定义命名
- 组件props类型:ComponentNameProps
- 复杂类型使用Type或Interface后缀
- 枚举类型使用复数形式
interface ModalProps {
title: string;
onClose: () => void;
}
type ButtonVariants = 'primary' | 'secondary' | 'text';
enum UserRoles {
Admin,
Editor,
Viewer
}
版本控制和变更日志
组件版本管理
- 遵循语义化版本(SemVer)
- 重大变更需要大版本升级
- 维护CHANGELOG.md记录变更
## [1.2.0] - 2023-05-15
### Added
- Button组件新增loading状态属性
### Changed
- Modal组件动画效果优化
### Fixed
- 修复Input组件在Safari浏览器下的样式问题
破坏性变更处理
- 废弃API应该给出警告
- 提供迁移指南
- 保持向后兼容至少一个主版本
// 废弃属性处理
function Button({ size, scale, ...props }) {
if (scale) {
console.warn('"scale" prop is deprecated, please use "size" instead');
size = scale;
}
return <button className={`btn-${size}`} {...props} />;
}
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn