炮打司令部,别让一个UI框架把你毁了

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情

话说自从React/Vue火起来后,无论是话题还是招聘,铺天盖地都是它们,好像只要精通了它们那就是妥妥的高级前端。这里我要炮打司令部:UI框架不是耶稣、不是救世主,太依赖它们反而会毁了你...

毁了你的视野

这些UI框架好似一道道高墙,把你软禁它们温暖的生态圈内,久了你也忘了外面还有广阔的世界。把UI层当作软件的全部,其它都成了附属品。

不需要状态管理、不需要MVC,不需要分层而治、不面向内聚解耦、不思考架构思想,一切都是Component、Hooks。

毁了你的技术

自从有了React/Vue,原生Dom操作就忘了,浏览器渲染原理也懒得学习了,JQ、RX等曾经的经典之作也无人知晓了,设计模式啥的好像也不上了。

你的技术栈就是UI框架的周边生态,离开React/Vue也不知道怎么写前端页面了...

毁了你的状态管理

有了Hooks/CompositionAPI就不需要单独的状态管理了?纯技术上来说或许是可以,但有没有想过Hooks/CompositionAPI都是特定UI框架的产物,与UI框架的渲染、生命周期深度耦合。 在JS国度中它们就像各种方言,再加上一些隐晦的心智负担,远没有一个Flux框架条理简单清晰。

而且,测试、监控、回滚一个“Action”多容易,你测试、监控、回滚一个“Hooks”试试...

当然并不是说Hooks就不好,不能用了。Hooks属于UI自己的魔术方法,让它处理自己份内事情当然得心应手,而其它非UI职责的事情,虽然它也可以干,但不合适。术有专攻,能说普通话为啥要用方言?

毁了你的工程

兄弟们打开你们的Component代码看看,是不是充斥着各种生命周期、各种数据定义、各种交互逻辑、各种业务逻辑、各种Ajax请求、各种路由跳转、各种Cookies/LocationStorage操作等等,轻轻松松几百行代码...

不要说有了Hooks/CompositionAPI就可以拆解了、就清晰了,No,只是可以更小粒度复用了,但可能变得更不直观了。

某些简单的数据交流,需要被Props传来传去,即便是我不需要,也要为我的儿孙代传,还要考虑传递和接收是同步还是异步、会不会出现闭包陷阱,会不会导致冗余渲染...好好的一条直路,被UI框架的渲染机制给带偏了。

将UI框架拉下神坛

UI层不是软件架构的全部,甚至连核心都不是,UI的指责只有2个:输入与输出,仅此而已。
它是问题的收集者和结果的反馈者,而不应当成为问题的解决者。

应用的核心是业务逻辑

那应用的核心是什么?是业务逻辑,而非UI交互逻辑。
UI的存在只是让用户更友好的使用系统,就像Dos、Linux系统不安装UI就不能用了吗?

那么现在问你一个问题:

如果你的应用不使用UI,用户可以通过命令来使用吗?

你可能会怼我说,不会有用户通过命令来使用我的应用,这是个没有意义的假设。然而,这种场景或许不是开放给用户使用的,而是给留合作伙伴、留给测试工具、留给日志分析用的呢?

不要过度依赖UI层

  • UI说:应用要改版,皮肤、交互、页面组织都要调整,要多久?
  • 产品说:把H5改改,做成小程序、APP吧,要多久?
  • 经理说:React人太难招了,要不我们换成Vue吧,要多久?
  • Leader说:Vue3出来了,我们升级为最新版吧,要多久?

业务逻辑不变,仅调整UI和其运行平台,问你要多久?一个星期?一个月?一年?还是...

同质化的UI框架

把UI框架看得太重?还在纠结使用“React”好还是“Vue”好?纠结“Ajax请求”是放“onCreate()”还是“onMount()”?每天都想着如何优化渲染性能?遇到异己总要去争论哪个更牛B?
试问 VUE3+JSX 与 React 又有多大的差别?

重提软件架构

把UI层变薄,它不过是渲染数据(输出)和收集动作(输入)。
让Controller、Model层回归,它们才是架构的C位,应用的大脑。
重提分层而治、重提MVC,让“客观、稳定”的业务逻辑不被“感性、多变”的UI逻辑干挠,保证核心逻辑可以跨越UI框架、跨越运行平台而运行。

重振Flux框架

MVC如何落地?大名鼎鼎的Flux架构就是一种 Controller 和 Model 的落地方案。
Redux/Vuex/Pinia、已及后面要推荐给大家使用的Elux,都可以看作它的变种。

从State到Model

MVVM应用中充斥着状态,有的用来描述Component的内部状况,它与Component唇齿相依,跟随Component诞生和销毁,这就是我们常说的ComponentState
还有一些状态,用来描述业务状态,与具体哪个Component没有直接关系,不存在复用与销毁,我们可以称它为Model

  • ComponentState 是UI逻辑,应当封装在Component里面,外界也无需知道。
  • Model 是业务逻辑,反映整个APP的状况,与Component无关,应当由Flux框架来统一管理。

从Event到Action

用户通过UI界面产生的人机交互事件,我们习惯叫"Event事件",而"Event事件"背后的业务目的我们可以叫"Action动作",它们一个是因一个是果,一个是表一个本。

  • 处理 Event 的 Handler 是UI逻辑,应当写在UI组件中
  • 处理 Action 的 Handler 是业务逻辑,应当写在Controller里面

举个具体的例子吧:"SubmitLoginForm|提交登录表单",通常要完成如下逻辑:

  1. 验证输入是否有效
  2. 验证当前用户是否已经登录
  3. 请求后端API,并等待返回
  4. 如果成功,保存用户信息,并跳回原页面
  5. 如果失败,提示错误,并留在原地

这是一个业务动作,因为它可以不依赖哪个具体UI而运行,用户可能通过“onClick事件”点击登录按钮来触发,也可能通过“onKeyPress”按下回车键来触发,甚至你可以直接让用户通过“Login命令”来触发。

所以“onSubmitLoginForm()”应当写在Controller而非UI组件中。
UI组件中只有"onLoginButtonClick()"或"onEnterKeyPress()",而它们往往也就一句话,就是Dispatch一个Action来触发Controller中的“onSubmitLoginForm()”

将业务逻辑移出UI组件,这样UI层就变薄了,回归到了它的本质:只负责收集业务动作,不负责处理它

改良Flux框架

传统的Flux框架也有痛点:

  • 全局中心化管理导致逻辑过于集中;
  • 单实例、不销毁容易造成信息累积爆炸;
  • DispatchAction机制过于简单,不适合处理前因后果的长流程业务。

这里要自荐给大家的 Elux框架,正是针对以上痛点进行了改良:

  • 虽然坚持全局中心化管理,但Elux提出“微模块”的概念,将应用拆分层独立自治的一个个“微模块”,每个微模块仅处理自己领域内的事情。
  • 不再单实例,每次路由变化都会产生一个新的空白Store,然后重新挑选有用的状态挂载,类似一种垃圾回收机制。
  • 提出了ActionBus的概念,让Action作为Model中的事件来广播。
  • 让Action的处理链条具备“协程”机制,更好的协同各业务动作之间的关联。

基于模型驱动

正是因为遵循了轻UI、重Model的设计思想,让Elux可以跨框架,可以使用React/Vue/更多其它UI框架来开发,可以不用为了React而学习NextJS,为了Vue又学习NuxtJS,UI框架已经变得没那么重要了。

正式因为分离了UI逻辑和业务逻辑,让Elux工程可以跨平台,可以用一种工程模式开发Web(浏览器)、Micro(微前端)、SSR(服务器渲染)、MP(小程序)、APP(手机应用)。

此致!欢迎交流:eluxjs.com

three-layers.jpg

猜你喜欢

转载自juejin.im/post/7110127638483566600