SwiftUI 系列 06|如何拆分组件,代码才不会越写越乱?
真正的组件拆分不是把大 View 切小,而是让结构边界、状态边界和复用边界同时变清楚
很多人一提“拆组件”,第一反应都是:
- 这个 View 太长了
- 把它拆成几个子 View 吧
这当然是一个开始,但如果拆分标准只剩“代码行数太多”,最后很容易出现另一种混乱:
- 文件确实变多了
- 但状态关系更难看懂了
- 组件名越来越抽象
- 父子之间传一堆参数
也就是说,页面并没有更清楚,只是从一个大文件变成了很多碎文件。
所以真正有效的组件拆分,不是“切小”,而是:
让结构边界、状态边界和复用边界同时更清楚。
一、先分清:你是在拆结构,还是在做复用
这是很多人最容易混在一起的两件事。
1. 为了结构可读性而拆
目的是让当前页面层次更清楚。
这类拆分即使只在一个页面里用一次,也完全合理。
2. 为了跨页面复用而拆
目的是抽出可重复使用的组件。
这类拆分要求边界更稳定、接口更克制。
如果这两类目的不分,最常见的后果就是:
- 明明只是想让页面清楚一点,结果过早抽成“通用组件”
- 或者明明这个模式已经重复很多次了,却仍然只当成局部子 View
所以组件拆分第一步不是动手,而是先判断你到底在解决哪类问题。
二、很多页面之所以越写越乱,不是因为不拆,而是 View 承担了太多角色
一个页面一旦同时承担这些事,就很容易迅速膨胀:
- 布局结构
- 本地 UI 状态
- 业务状态映射
- 数据格式化
- 交互动作拼装
这时你会发现,代码长不是根因,真正的问题是:
- 哪些逻辑属于 View
- 哪些逻辑应该在外面
- 哪些局部结构值得独立表达
组件拆分真正的价值,是逼你重新做这层边界判断。
三、最值得先拆出去的,通常不是“最通用的”,而是“在当前页面语义最完整的一块”
很多人一拆组件,就急着找最通用的部分。
但真实开发里,更稳的做法往往是先拆那些在当前页面里语义完整的一块。
例如:
- 资料头部区
- 文章摘要卡片
- 设置项行
- 空态区块
这些结构的好处是:
- 它们在页面里本来就是一个独立单元
- 拆出去后结构语义更清楚
- 即使暂时不复用,也不会亏
这比一开始就想抽出一个“超级通用 Cell 容器”稳得多。
四、组件一旦拆出去,接口就变成了真正的设计问题
组件拆分最大的价值之一,是它会逼你思考接口。
你很快会发现:
- 这个子组件到底该拿原始模型,还是拿格式化后的展示数据
- 它需要知道点击后怎么跳,还是只暴露一个 action
- 它应该拥有本地状态,还是由父层驱动
这些问题如果不想清楚,组件很容易变成:
- 参数一大堆
- 业务语义不清
- 父层什么都得知道
所以组件拆分不是体力活,而是接口设计活。
五、一个非常常见的坏味道:把“局部结构拆分”和“业务逻辑切分”混在一起
比如某个列表卡片,如果你拆出去后它同时负责:
- 布局展示
- 数据格式化
- 埋点
- 点击后的业务判断
那这个组件虽然独立了,但其实职责还是很混。
更稳的做法通常是:
- 展示组件尽量专注展示
- 业务决策尽量留在更高层
- 子组件暴露必要事件,不直接吞下整个业务流程
否则组件越拆,逻辑会越碎,但复杂度不会下降。
六、什么时候不该急着抽“通用组件”
这是很多 SwiftUI 项目很容易过度设计的点。
如果一个模式目前只在一个页面里刚出现一次,而且:
- 业务结构还不稳定
- UI 细节还在快速变化
- 你自己都还不确定边界
那这时更适合先拆成页面内的局部子 View,而不是立刻上升成通用组件。
因为“过早复用”经常会带来一个后果:
- 组件接口变得很宽
- 为了兼容未来可能的场景,先塞很多选项
结果反而比不拆更难维护。
七、一个实用判断:这个子结构如果单独拿出来,别人能说清它是什么吗
这是我很常用的判断方式。
如果某个子结构拿出来后,大家能自然地说:
- 这是一个用户资料头部
- 这是一个设置项行
- 这是一个文章摘要卡片
那它通常适合拆。
如果拿出来之后只能说:
- 这是一个“组合容器”
- 这是一个“内容区块 View”
- 这是一个“多场景卡片壳”
那大概率说明它的语义还不够稳定,拆分时机可能还没到。
八、结论:组件拆分真正要追求的,不是文件变小,而是边界更清楚
如果只用一句话总结,我会说:
SwiftUI 组件拆分真正有效的标准,不是把一个大 View 切成很多小 View,而是拆完之后结构边界、状态边界和接口边界都比原来更清楚。
只有这样,组件越拆越轻;否则就很容易变成文件变多了,系统却更难读。