❌「不要再封装组件了!」我把 UI 重构成了纯函数式
"组件封装写多了,有没有一种感觉:你根本不知道你自己封了个啥。"
我之前在项目里封了 60+ 个 UI 组件,按钮就有三种:Button、MyButton、SubmitButton,结果样式越来越乱,props 越来越多,调样式就像打仗一样。
后来我决定把整个 UI 层彻底重构为函数式。
这篇文章我来讲讲:为什么不再封装组件,而是用 Tailwind + 纯函数构建 UI,并分享我实际项目中的改造过程。
🤯 封装组件的幻觉
我们都觉得"封装组件=规范",但实际情况呢?
ini
<MyButton
type="primary"
variant="ghost"
color="red"
theme="dark"
danger
size="small"
/>
看着像规范,其实已经成为"props 分布式样式控制中心"。
问题包括:
- 样式靠 props 判断,逻辑越来越臃肿
- 组件之间样式不一致,改一个按钮影响一堆地方
- 想换个主题,得重构全部组件
- 甚至某些 props 决定逻辑 + UI 的组合,根本不好维护
✅ 我怎么改的?直接函数式构建样式
我保留最基础的组件(如 Button 用 ),其他一律改成纯函数样式生成:
arduino
// ui/button.ts
export function useButtonClass({
variant = 'primary',
ghost = false,
size = 'base',
}: {
variant?: 'primary' | 'danger' | 'default'
ghost?: boolean
size?: 'base' | 'sm' | 'lg'
}) {
return cn(
'inline-flex items-center justify-center font-medium rounded transition',
size === 'sm' && 'px-2 py-1 text-sm',
size === 'lg' && 'px-5 py-3 text-lg',
size === 'base' && 'px-4 py-2 text-base',
variant === 'primary' && 'bg-blue-600 text-white hover:bg-blue-700',
variant === 'danger' && 'bg-red-500 text-white hover:bg-red-600',
ghost && 'bg-transparent border hover:underline'
)
}
使用方式:
css
<button className={useButtonClass({ variant: 'danger', ghost: true })}>
删除
</button>
纯净、语义清晰、无副作用。
🧩 真实项目效果对比
💢 之前:
ini
<MyButton type="danger" ghost size="small" onClick={handleDelete}>
删除
</MyButton>
- 组件需要解构 props 做判断
- 样式嵌套多层,覆盖麻烦
- 动态变更样式要改组件内部逻辑
✨ 现在:
ini
<button
className={useButtonClass({ variant: 'danger', ghost: true, size: 'sm' })}
onClick={handleDelete}
>
删除
</button>
- 样式全部在 class 中生成
- 完全由调用方控制,无副作用
- 支持 tailwind 动态主题、响应式无痛切换
🌈 弹窗、输入框一样适用
css
{showModal && (
<div className={modalClass()}>
<h2 className="text-lg font-bold">确认删除?</h2>
<div className="flex gap-2 mt-4">
<button className={useButtonClass({ variant: 'danger' })}>确认</button>
<button className={useButtonClass({ variant: 'default', ghost: true })}>
取消
</button>
</div>
</div>
)}
组件自由组合,样式不依赖"封装逻辑"。
🚫 不适合的情况
不是所有场景都推荐用函数式样式替代组件封装:
场景 | 推荐方式 |
---|---|
小按钮、输入框、表单项等基础控件 | ✅ 函数样式 |
富交互组件(如 Drawer、DatePicker) | ✅ 组件封装 |
行为逻辑重(如权限/校验/联动) | ✅ 封装组件组合 |
我的做法是:最小颗粒度用函数封装样式,复杂交互用组件包逻辑。
📦 补充工具推荐
- clsx / classnames:动态 class 拼接
- tailwind-variants:类函数式样式生成器(更高级)
- tailwindcss-animate:添加统一动画支持
✅ 总结:组件 ≠ 万能解药
React 本质上是 UI = f(state)。封装组件容易让我们忽视状态和样式之间的映射关系。
而样式函数就是在做真正的"UI 映射" :不同参数 → 不同视觉 → 统一逻辑。
组件是树,样式是数据,UI 是表达。
函数式构建样式,是表达力与灵活性的平衡。
🧩 项目预告
我正在封装一套完整的「函数式样式 UI 系统」,可用于 React + Tailwind 项目中快速构建高一致性视觉体验。
欢迎点赞 + 收藏支持我继续更新 ✨
如果你也想试试这种写法,评论区一起交流!