为什么 React 比 Vue 更适合集成 TS

2,313 阅读6分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

导读

本文是个短篇,是笔者在探索 Vue3 + TSX 最佳实践的过程中的一些感悟,也算是《Vue3 + TS 最佳实践》的副产品。私以为这些“新发现”会有助于帮助大家理解 React 和 Vue 的设计理念,特整理成文,望起到抛砖引玉的作用。

背景

笔者有 2 年多 React + hooks + TS 的开发经验,可以说开发体验比 Class Component + Redux 要好太多了。当渡过了刚引入 TS 的不适期之后,写代码的感觉可以用酣畅淋漓来形容。如果让我再换回老写法,我是绝对不愿意的。

近期因工作原因,技术栈转成了 Vue3。又恰逢团队尝试引入 TS,遂做了许多 Vue3 + TS 最佳实践方面的研究。当静下心来思考、体会,尤其是把两个优秀的框架进行对比时,豁然体会到了一丝 React 设计思想的奥妙,内心甚是欣喜。忍不住要分享出来,望大家莫要见笑。

正文

TS 的好处在之前的文章中(如《Vue3 + TS 最佳实践》)已经提过很多次了,这里就不再赘述了。本文会以 TS 作为切入点,通过分析 React 和 Vue 对于 TS 的支持来体现二者设计理念的不同。

React 在结合 TS 方面为什么会这么成功

关键词:抽象

React 在 v16.8 引入 hooks 的概念之后,所有场景都可以用 Functional Component + hooks 来实现。这意味着“组件就是 function”,而 hooks 从使用层面来看也是一些封装好的 function。也就是说在 React 的体系里,使用层面就只剩下了 function,已经实现了极致简单的抽象。这里可以用拍案叫绝来形容,当笔者意识到这点的精妙之处时,内心是非常震撼与激动的。

要知道,把一个非常复杂,不可穷举的场景抽象成一个,注意是“一个”,概念来表达,是一件多么困难的事。用个不太恰当的比喻,如果把一个事物抽象成两个概念来表达的难度是 10 的话,那抽象成只有一个概念的难度我愿意给出 100。这么说还是很虚,我们还是接着往下看。

言归正传,笔者认为,此功劳应归于 hooks。公共逻辑的复用经历了 HOC => renderProps => hooks(详见 Do Hooks replace render props and higher-order components?)。hooks 的出现不仅优雅地解决了公共逻辑复用的问题,甚至直接把组件内部的状态维护也给抽象出去了。说 hooks 的出现是前端的又一次革命,一点也不为过。在笔者看来,能与其相提并论的,是 Virtual DOM 的发明。

只剩下 function 也就意味着绝对的简单纯粹,与 TS 的结合自然是无比顺畅,完美契合。这就是高度抽象的好处之一。

JSX 在其中充当的角色

关键词:解耦

JSX 的本质只是 JS 的一种语法糖,为了让开发者更加方便的写 DOM 标签,其最终会被编译工具转换成 JS 代码(通常为 render 函数),其本质也可以理解为 function。

另外,JSX 实际上只负责“展示层面”的实现,功能非常单一。其他非常复杂的逻辑,如 if-else,for-loop 等,都是由 JS 承载的,这是一个非常关键的解耦。甚至可以简单粗暴的大胆断言,JSX 在使用层面,未来几乎不会有任何大的变化,也不需要有变化。相对的,负责逻辑部分的 JS(ES)一定会不断的迭代升级,推陈出新,增强能力,提升开发体验。

再说 TS。对于 JSX 的适配,只需要实现一次即可,因为其非常稳定;而对于 JS 的适配,是 TS 必须实现的任务,自不必说。所以,JSX + TS,即 TSX 将会随着 TS 的迭代,自然迭代,无需付出太多成本。这就是高度解耦的好处之一。

JSX vs. Vue Template(SFC)

关键词:性能

Vue Template 实际上也可以理解为一种语法糖,其最终也会被编译为 render 函数(关于它的优点可先查看官方文档 为什么要使用 SFC)。与 JSX 不同的是,它还耦合了一些逻辑在里面,比如 if-else、for-loop、emits 等。这意味着,如果 Template 想要与 TS 结合,必须把其耦合的逻辑给处理好。而且在 Template 中无法使用一些 ES 的新特性,比如解构赋值(在二次封装组件时很常用)。这样对比来看,React 充分解耦带来的好处,就比较明显了。

但是,就是因为 Template 耦合了逻辑在里面,这也增加了某些语义的确定性,Vue 就可以利用这些确定性,帮你做一些优化的事情。比如 Vue3 的静态提升、事件侦听器缓存等。如果 React 想要实现类似的优化,就需要使用到 useMemouseCallback 等手段了,相信能正确并熟练运用这些优化手段的人不会是多数。这意味着,在无法保证程序员水平的情况下,Vue 在大多数场景的性能方面,下限大概率要比 React 高

除此之外,Vue 的 SFC 写法,使得 templatescriptstyle 之间的数据复用成为可能。实际上 Vue 已经有了在 style 中直接使用 script 中变量的能力,详见 状态驱动的动态 CSS。如果想实现类似的功能,React 必须要自己引入 css-in-js 的技术方案。不得不吐槽,React 生态向来都是这样,想用点啥都得自己搭。相对来说,Vue 在生态方面要好用的多,当然,丰富度上前者还是占绝对优势。

说回 TS。既然 Template 是语法糖,其本质还是 render 函数,那么理论上还是能够像 JSX 一样实现 TS 的支持的,只是需要适配的逻辑会多很多。好在 Volar 已经很大程度的解决了这个问题,目前来看还没发现明显的问题。

结语

全文可谓:“说 TS 是假,对比 React 和 Vue 是真”。本文列出了抽象、解耦、性能三个方面的思考与对比,笔者实在是深深地折服于 React 和 Vue 作者的智慧与思想,学习过后自认为在架构设计方面又有了一丝会心。

React 和 Vue 各有优缺点(废话),但是就笔者个人而言,目前更仰慕 React 多一些,毕竟我们还身处于 hooks 带来的革命当中。笔者早些年是更喜欢 Vue 的,因为其亲民的设计、平滑的学习曲线、完善的文档更加的接地气,统一的生态工具管理,使用体验更是比 React 好太多。只是最近 TS 的加入,配合上 hooks,严重的打破了原有的格局。现在看来,Vue 正在往回追,而且已经追回来不少了。希望后面 Vue 能够再放出个大招,让笔者再拍案叫绝一次。最后,以笔者有限的文化积累来结个尾,与大家共勉。

子曰:“温故而知新,可以为师矣。”——《论语·为政》