前端架构:分离工作流编排与UI反应

前端应用中,状态和事件常被混淆,导致工作流逻辑分散在视图模型和组件中。本文通过案例展示问题,并提出将工作流编排与UI反应分离的实用方法。
前端架构的隐形杀手:状态与事件的混淆
前端应用架构很少因为一次糟糕的决策而崩塌,它通常是逐渐腐化的:视图模型引入了 toast 库,模态组件开始协调页面跳转,通知消息变成了可观察状态。随着时间推移,逻辑散落在不同层级、组件和视图模型中,层与层之间的边界逐渐模糊。
这些决策单独看似乎都合理,问题往往在后期才暴露——当多个视图模型、组件和渲染逻辑共同管理一个工作流时,架构就会变得混乱。根本原因在于,开发者常常将两种截然不同的概念混为一谈:状态(State) 和 事件(Events)。
状态用于描述持续存在的事物:实体、加载状态、筛选条件、缓存等。而事件则不同,它们不是“存在”的,而是“发生”的:登录成功、会话过期、验证失败等。事件发生后,应用的其他部分做出反应,然后事件就消失了。这些反应可能包括显示 toast、关闭模态框、重定向用户或展示验证反馈。
但在实际应用中,事件常常被错误地当作状态处理。视图模型维护一个标志来显示通知,组件中某个 effect 监听状态变化来触发跳转,或者点击处理程序等待响应后执行下一步。这种做法的直接后果是:视图模型开始了解 UI 行为,而组件开始了解背后的工作流。
逻辑通常落在哪里:两个典型反模式
1. 视图模型拥有 UI 基础设施
这是最常见的情况。下面是一个登录视图模型的例子,它等待 API 响应后直接处理 UI 行为:显示错误、重定向用户、关闭模态框。
class LoginVM {
@action
public async login() {
const result = await api.login({
email: this.email,
password: this.password,
})
if (!result.data.isSuccess) {
toast.error(result.error.message)
return
}
navigate('/dashboard')
closeModal()
}
}
初看之下,这似乎没问题:登录流程集中在一处,组件保持简单。但问题在于,UI 逻辑开始渗入视图模型。它现在决定了何时导航、何时显示通知、何时关闭模态框。此时,视图模型不再只负责登录流程,它还知道了 UI 应该如何响应它。
2. 工作流编排落入 UI 层
另一种做法是将 UI 特定逻辑从视图模型中抽离,直接在组件中处理。视图模型只处理登录并返回结果,组件决定后续操作。
// 伪代码示例
const handleLogin = async () => {
const result = await store.login()
if (!result.data.isSuccess) {
toast.error(result.error.message)
return
}
analytics.track('login_success')
closeModal()
navigate('/dashboard')
refreshCurrentUser()
}
有人会说这很合理:视图模型不依赖 UI,组件决定如何处理结果。但组件已经不只是响应 UI 了——refreshCurrentUser() 本身就是工作流的一部分,现在工作流被拆散在视图模型和组件两处。随着步骤增多,这种拆分会让代码难以追踪和维护。
核心原则:事件与状态分离
解决这个问题的关键在于,明确区分“事件”和“状态”,并让它们各司其职。事件是瞬时的,应该通过事件通道(如消息总线)传递,由专门的处理器响应;状态是持久的,应该由视图模型或 store 管理。
对于开发者而言,这意味着:
- 视图模型只负责业务逻辑和状态管理,不直接调用 UI API(如 toast、navigate)
- 组件只负责渲染和用户交互,不承载工作流编排
- 工作流编排应该放在独立的服务或控制器中,统一处理事件、调用 API、协调 UI 反应
这种架构带来的实际好处是:
- 可测试性提升——工作流逻辑可以脱离 UI 进行单元测试
- 可维护性增强——修改 UI 行为不会影响业务逻辑,反之亦然
- 复用性提高——同一套工作流可以被不同 UI(Web、移动端)复用
对于使用 MVVM 架构(如 MobX、Vue)的开发者,建议将事件处理放在独立的 service 层,通过依赖注入方式传递给视图模型。对于 React 开发者,可以考虑使用 reducer 或自定义 hook 来封装工作流,将 UI 反应作为副作用分离出来。
最终,前端架构的健康不在于某一次的完美设计,而在于持续维护层与层之间的清晰边界。区分状态与事件,就是守住这条边界的第一步。
本文基于 Hacker Noon 的公开内容,由 AI 辅助整理改写后发布。
原标题:Separating Workflow Orchestration from UI Reactions in Frontend Applications
阅读原文