Appearance
页面至少要交代的状态,以及三种抽象不要混用
需求一旦不是在旧版本上小步加字段,而是交互和数据结构一起改,公共代码就很容易失效。这时与其先讨论“复用率低”,不如先把两件更小的事分开:页面要向用户交代哪些状态,以及一段代码到底该是组件、Hook 还是工具函数。
一个交互至少有这些状态
主路径只覆盖“请求成功且有数据”。真正让页面看起来不稳定的,是没被设计的分支:
- 加载中
- 空数据
- 刷新时旧数据还在不在
- 接口失败,以及能不能重试
- 文案长过容器
- 连续点击要不要防抖或节流
- 事件参数要不要校验
这些状态应该在做概要设计时就和接口一起定,而不是等联调时用空页面和重复提交补回来。加载中还没结束,就不要先走“数据为空”的分支,否则用户会先看见空状态,再看见内容。
小程序和 App 还要额外留出后续修改的位置:新需求几乎总会改旧页面。把数量、文案和分支写死,下一次就只能复制一份。
组件、Hook、工具函数各拿一种变化
三种抽象对应三种变化,不要因为“这段代码出现了两次”就选同一种抽法。
组件抽象的是一块界面和它的交互。一个带远程搜索的选择器,如果两处的结构、值和事件一致,就应该是组件。
Hook 抽象的是带状态的过程。它返回状态和操作,调用方不需要知道请求何时开始、结果放在哪个 ref。没有状态、只是把一段逻辑搬出组件的函数,不必做成 Hook。
工具函数抽象的是一次计算:格式化、集合运算、字段映射。它不读写组件状态,也不发起和界面绑定的请求。
判断顺序可以很短:
- 只是输入输出,没有生命周期:工具函数
- 要在多处保持同一份加载、缓存或订阅过程:Hook
- 要在多处保持同一块界面:组件
界面现在相似,但空状态、权限和提交字段会分开演化时,不要提前抽成一个组件。那会把业务分支塞回公共层。具体的抽取边界见逻辑、表单和组件该抽到哪一层。
规范要写的是这些场景,不只是格式
格式化解决的是阅读。体验上的规范要规定:什么时候必须有骨架屏,什么时候必须禁止重复提交,列表失败时长什么样。没有这层约定,每个页面都会凭感觉补一种状态,最后公共组件也无从对齐。