web 前端组件拆分与复用策略

组件拆分原则(原子设计思想进阶)

原子级组件

  • 基础 UI 元素:按钮、输入框、图标等
  • 特点:无状态或简单状态,零业务逻辑
  • 示例:<Button><Input>

分子级组件

  • 原子组件的组合:搜索框 = 输入框 + 按钮
  • 特点:封装简单交互逻辑,可复用
  • 示例:<SearchBar onSearch={callback}>

有机体级组件

  • 业务模块:商品卡片 = 图片 + 标题 + 价格 + 评分
  • 特点:包含业务数据结构和样式,部分复用
  • 示例:<ProductCard data={product}>

模板级组件

  • 页面骨架:布局结构(Header/Footer/Sidebar)
  • 特点:通过插槽(Slots)组织区域
  • 示例:
    <PageLayout>
      <template #header><Header /></template>
      <template #content><RouterView /></template>
    </PageLayout>

页面级组件

  • 路由对应视图:组合多个有机体
  • 特点:包含数据获取和状态管理,不可复用
  • 示例:/product-detail 页面

复用策略金字塔(优先级从高到低)

配置化驱动(最佳实践)

  • 通过 Props 控制行为和样式
  • 示例:
    <Table 
      columns={[...]} 
      data={[...]}
      pagination={{ pageSize: 10 }}
    />

组合模式(React/Vue 核心思想)

  • 使用 children 或插槽注入内容
  • 示例:
    <Modal>
      <CustomForm /> {/* 内部内容可自由替换 */}
    </Modal>

自定义 Hooks / Composables(逻辑复用)

  • 抽离通用逻辑(如数据请求、拖拽逻辑)
  • 示例:
    // 复用数据请求逻辑
    const { data, loading } = useFetch('/api/data');

高阶组件/Render Props(复杂场景)

  • 适用于跨组件逻辑复用(如权限校验)
  • 示例:
    <AuthGuard role="admin">
      <AdminPanel />
    </AuthGuard>

全局组件库(基础组件复用)

  • 将原子/分子组件发布为独立 npm 包
  • 维护统一的版本和文档(如 Storybook)

关键决策点

何时拆分?

场景 解决方案
相同 UI 出现 3 次以上 抽取为可配置组件
组件代码 > 300 行 按功能拆分子组件
多个文件引用同一段逻辑 抽离为自定义 Hook

避免过度拆分

// ❌ 错误示范:无意义的原子化
const RedText = ({ children }) => <p style={{ color: 'red' }}>{children}</p>;

// ✅ 正确做法:通过 Props 控制
const Text = ({ color, children }) => <p style={{ color }}>{children}</p>;

可维护性保障

  • 单一职责原则
    • 每个组件只解决一个问题(如 PriceDisplay 只处理价格格式化)
  • 受控/非受控模式
    • 同时支持受控(value + onChange)和非受控(defaultValue)行为
  • 严格的 TypeScript 类型
    interface ButtonProps {
      variant: 'primary' | 'ghost'; // 明确可选值
      size?: 'sm' | 'md';          // 可选属性
      onClick: () => void;         // 函数类型
    }
  • 文档驱动开发
    • 使用 Storybook 或 dumi 可视化组件用例
    • 自动生成 Props 文档

业务场景实践

场景:电商商品卡片

// 1. 原子组件
<Image src={...} lazyLoad />

// 2. 分子组件
<PriceDisplay value={99} currency="CNY" />

// 3. 有机体组件(业务卡片)
<ProductCard 
  data={product}
  // 差异化配置
  showDiscountBadge={true}
  layout="vertical"
/>

// 4. 通过组合扩展功能
<ProductCard>
  <Slot name="footer">
    <CountdownTimer endTime={...} /> {/* 定制化内容 */}
  </Slot>
</ProductCard>

避免的常见陷阱

  • Prop Drilling 地狱
    • 使用 Context/状态管理库传递深层数据
  • 滥用全局状态
    • 表单状态应优先保留在组件内部
  • 忽略性能优化
    • 对大数据列表使用虚拟滚动
    • 使用 React.memo/useMemo 减少渲染
  • 组件与业务逻辑强耦合
    • 错误示例:<UserCardWithOrderHistory />
    • 正确方案:<UserCard extraContent={<OrderHistory />}>

总结:组件化心智模型

[ 原子组件 ] → [ 分子组件 ] → [ 业务组件 ]  
      ↑               ↑             ↑
  基础UI库       逻辑复用       页面组装

遵循 「高内聚、低耦合」 原则:

  • 向上通过 Props 控制行为
  • 向下通过 Slots 提供扩展能力
  • 横向通过 Hooks 复用逻辑

通过分层设计和合理的复用策略,可显著提升代码可维护性和团队协作效率。