一、组件封装的焦点原则
1.1 设计原则概览
1.2 组件生命周期
二、组件设计准则
2.1 单一职责原则
示例:
- // Bad: 混合职责
- function UserProfile({ user }) {
- return (
- <div>
- <h2>{user.name}</h2>
- <img src={user.avatar} alt="avatar" />
- <button onClick={() => sendMessage(user.id)}>Send Message</button>
- </div>
- )
- }
- // Good: 职责分离
- function UserProfile({ user }) {
- return (
- <div>
- <UserInfo user={user} />
- <UserActions userId={user.id} />
- </div>
- )
- }
- function UserInfo({ user }) {
- return (
- <>
- <h2>{user.name}</h2>
- <img src={user.avatar} alt="avatar" />
- </>
- )
- }
- function UserActions({ userId }) {
- return (
- <button onClick={() => sendMessage(userId)}>Send Message</button>
- )
- }
复制代码 2.2 高内聚低耦合
- 内部逻辑紧密相干
- 外部依靠最小化
- 通过Props控制行为
示例:
- // Bad: 高耦合
- function ProductList({ products }) {
- const [cart, setCart] = useState([])
-
- return (
- <ul>
- {products.map(product => (
- <li key={product.id}>
- {product.name}
- <button onClick={() => setCart([...cart, product])}>
- Add to Cart
- </button>
- </li>
- ))}
- </ul>
- )
- }
- // Good: 低耦合
- function ProductList({ products, onAddToCart }) {
- return (
- <ul>
- {products.map(product => (
- <li key={product.id}>
- {product.name}
- <button onClick={() => onAddToCart(product)}>
- Add to Cart
- </button>
- </li>
- ))}
- </ul>
- )
- }
复制代码 三、组件接口设计
3.1 Props设计规范
3.2 代码示例
- interface ButtonProps {
- // 基础属性
- type?: 'primary' | 'secondary' | 'danger'
- size?: 'small' | 'medium' | 'large'
- disabled?: boolean
-
- // 事件处理
- onClick?: (event: React.MouseEvent) => void
-
- // 内容相关
- icon?: React.ReactNode
- children: React.ReactNode
- }
- const Button: React.FC<ButtonProps> = ({
- type = 'primary',
- size = 'medium',
- disabled = false,
- onClick,
- icon,
- children
- }) => {
- return (
- <button
- className={`btn btn-${type} btn-${size}`}
- disabled={disabled}
- onClick={onClick}
- >
- {icon && <span className="btn-icon">{icon}</span>}
- {children}
- </button>
- )
- }
复制代码 四、组件状态管理
4.1 状态设计原则
4.2 代码示例
- function useToggle(initialValue = false) {
- const [value, setValue] = useState(initialValue)
-
- const toggle = useCallback(() => {
- setValue(v => !v)
- }, [])
-
- return [value, toggle]
- }
- function Accordion({ title, children }) {
- const [isOpen, toggle] = useToggle(false)
-
- return (
- <div className="accordion">
- <div className="header" onClick={toggle}>
- {title}
- <Icon name={isOpen ? 'chevron-up' : 'chevron-down'} />
- </div>
- {isOpen && (
- <div className="content">
- {children}
- </div>
- )}
- </div>
- )
- }
复制代码 五、组件样式处理惩罚
5.1 样式方案对比
方案优点缺点CSS Modules局部作用域,避免冲突动态样式支持有限CSS-in-JS动态样式,组件化运行时开销,SSR问题Utility CSS高性能,一致性学习曲线,可读性差BEM语义清晰,可维护性好类名冗长,灵活性不足 5.2 代码示例
- // CSS Modules
- import styles from './Button.module.css'
- function Button({ children }) {
- return (
- <button className={styles.button}>
- {children}
- </button>
- )
- }
- // styled-components
- const StyledButton = styled.button`
- padding: 0.5rem 1rem;
- border-radius: 4px;
- background: ${props => props.primary ? 'blue' : 'gray'};
- `
- function Button({ primary, children }) {
- return (
- <StyledButton primary={primary}>
- {children}
- </StyledButton>
- )
- }
复制代码 六、组件测试方案
6.1 测试金字塔
6.2 测试示例
- // 单元测试
- test('Button renders correctly', () => {
- const { getByText } = render(<Button>Click me</Button>)
- expect(getByText('Click me')).toBeInTheDocument()
- })
- // 集成测试
- test('Accordion toggles content', async () => {
- const { getByText, queryByText } = render(
- <Accordion title="Section 1">
- <p>Content</p>
- </Accordion>
- )
-
- expect(queryByText('Content')).not.toBeInTheDocument()
-
- fireEvent.click(getByText('Section 1'))
- expect(getByText('Content')).toBeInTheDocument()
- })
复制代码 七、组件文档规范
7.1 文档结构
- # ComponentName
- ## Description
- Brief description of the component
- ## Props
- | Prop | Type | Default | Description |
- |------|------|---------|-------------|
- | prop1 | string | - | Description |
- | prop2 | number | 0 | Description |
- ## Usage
- ```jsx
- <ComponentName prop1="value" />
复制代码 Examples
Basic Usage
Advanced Usage
- <ComponentName prop1="value" />
复制代码- ### 7.2 Storybook示例
- ```javascript
- export default {
- title: 'Components/Button',
- component: Button,
- argTypes: {
- type: {
- control: {
- type: 'select',
- options: ['primary', 'secondary', 'danger']
- }
- }
- }
- }
- const Template = (args) => <Button {...args} />
- export const Primary = Template.bind({})
- Primary.args = {
- type: 'primary',
- children: 'Primary Button'
- }
复制代码 八、组件发布流程
8.1 发布流程
8.2 版本控制示例
- # 版本更新
- npm version patch # 修复bug
- npm version minor # 新增功能
- npm version major # 不兼容变更
- # 发布
- npm publish
- # 生成CHANGELOG
- npx conventional-changelog -p angular -i CHANGELOG.md -s
复制代码 总结:本文从设计原则到详细实现详细讲授了组件封装的最佳实践,包含接口设计、状态管理、样式处理惩罚、测试方案等焦点内容。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |