关于 Vue 选项式与组合式 API 的一些思考

关于 Vue 选项式与组合式 API 的一些思考

某种意义上,Vue 3 组合式 API 反而引入了比 Vue 2 更重的心智负担。

切换到 Vue 3 已经很久了,组合式 API、setup,都用着很舒服。因为某些原因,最近又写了 Vue 2 的一些代码了,反而感觉写起来有另一种奇怪的舒适感。要形容的话,就是感觉比 Vue 3 好像还更省心一点。

仔细想想,倒也的确如此。平时用 Vue 3 Composition API 时还真没 Vue 2 时全绑 this 来得省心,某种意义上。

Vue 3 引入组合式 API 的苦衷可以理解。一方面,this 确实是个问题严重的东西,很容易在回调中丢掉,而很多时候 TS 甚至报不出来错,写代码时不得不时刻留意 this 的作用域问题确实很令人难过。

另一方面,选项式 API 本身对 TS 不友好,而组合式 API 那种简洁的“Type-Only”方式就更难实现,因为在选项式 API 里面你没有一个合适的位置来放类型……你只能 type: Function as PropType<...> 这样,这种断言真的挺不优雅的,而且这种方式 Vue 没办法在运行时做更深的检验,在这个例子里,Vue 只能检验这个 prop 是不是函数,返回类型甚至参数数量它都没办法检验。

但是仔细想想,似乎为了解决选项式 API 的问题并不一定要引入组合式 API. 我怀疑这里边或许有一些 React Hooks 爱好者在里边起作用……组合式 API 带来了新的思维负担,其中一个就是 ref.value,而且还丢失了把属性挂在 this 上的思维负担优势……至少我这么认为。而且,this.$refs,this.$storethis.$router 这些真的很快乐啊。虽然现在 Vue 3 也能直接在 template 里这么写,但显然不能在 script 里这么写了,还是差点意思。

其实也有一个避免 this 但吸取选项式 API 优势的好办法嘛:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
export default component((self) => ({
name: 'post',
data: () => ({ show: true, }),
props: withDefaults(
type({
time: 'string',
'author?': 'string',
}),
{
author: () => 'Unknown',
}
),
mounted: () => {
console.log(self.time, self.author);
},
methods: {
hidePost: () => {
self.show = false;
},
showPost: () => {
self.show = true;
},
},
});

在这里,self 是个代理对象,替代了 this 的功能,这样就避免了 this 动态作用域的问题。

而且,类型校验的问题也解决了,在这里使用了 Arktype 来做校验,这使得框架能够获得精准的类型,以此进行检验。

Vue 2 的年代里,人们还普遍信任于 this 与面向对象,ES6 中 class 的引入也使各大框架纷纷考虑将其利用起来。当时,似乎很少有人想到可以使用一些简单的方法避免 this React 且也想不到有什么必要这么做。后来,React “倒行逆施”地引入了 FC,重新引起了各框架的思考,这才使框架们呈现了现在的状况。现在,大家一致认为通过闭包捕获的变量更加安全与可信。

并且,当时人们对 TS 的利用也没有现在这么疯狂。当时的人们认为 JS 还是一门非常动态的语言,TS 顶多用来补足一些常见的类型。而现在,事情已经完全倒转了。

或许我有可能真的实现这样一个新的框架?它相比 Vue 更类型安全,并且吸取了选项式 API 的优点,同时使用 JSX 以获得更好的兼容性。或许如此。但是这显然需要投入太多时间,我对此还不那么有信心。


关于 Vue 选项式与组合式 API 的一些思考
https://snowfly-t.github.io/2023/06/10/关于Vue选项式与组合式API的一些思考/
作者
Snowflyt
发布于
2023年6月10日
许可协议