为什么响应性语法糖最终被废弃了?尤雨溪也曾经试图让你不用写 .value

你将永远需要在 Vue3 中写 .value

前言

相信有不少新手在初次接触 Vue3 的组合式 API 时都会产生一个疑问:"为什么一定要写 .value ?",一些 Vue3 老玩家也认为到处写 .value 十分不优雅。

那么有没有办法能不用写 .value 呢?有的兄弟,至少曾经有的,那就是响应性语法糖,可惜在 Vue 3.4 之后已经被移除了。

响应性语法糖是如何实现免去 .value 的?这一特性为何最终被废弃了呢?

响应性语法糖

Vue 的响应性语法糖是一个编译时的转换步骤,让我们可以像这样书写代码:

javascript 复制代码
<script setup>
let count = $ref(0)

console.log(count)

function increment() { 
    count++ 
} 
</script> 

<template> 
    <button @click="increment">{{ count }}</button> 
</template>

这里的 $ref() 方法是一个编译时的宏命令 :它不是一个真实的、在运行时会调用的方法,而是用作 Vue 编译器的标记。使用 $ref() 声明的响应式变量可以直接读取与修改,无需 .value。

上面例子中 <script> 部分的代码会被编译成下面这样,在代码中自动加上 .value:

javascript 复制代码
import { ref } from 'vue'

let count = ref(0)

console.log(count.value)

function increment() {
  count.value++
}

每一个会返回 ref 的响应式 API 都有一个相对应的、以 $ 为前缀的宏函数。包括以下这些 API:

通过 $() 解构

当一个组合式函数返回包含数个 ref 的对象,我们希望解构得到这些 ref,并且在后续使用它们时也不用写 .value 时,可以使用 $() 这个宏:

javascript 复制代码
import { useMouse } from '@vueuse/core'

const { x, y } = $(useMouse())

// x,y 和用 $ref 声明的响应式变量一样,不用写 .value
console.log(x, y)

通过 $$() 防止响应性丢失

假设有一个期望接收一个 ref 对象为参数的函数:

javascript 复制代码
function trackChange(x: Ref<number>) {
  watch(x, (x) => {
    console.log('x 改变了!')
  })
}

let count = $ref(0)
trackChange(count) // 无效!

上面的例子不会正常工作,因为代码被编译成了这样子:

javascript 复制代码
let count = ref(0)
trackChange(count.value)

trackChange 函数期望接收的参数是一个 ref 类型值,而我们传入的 count.value 实际是一个 number 类型。

对于一个使用 $ref() 声明的响应式变量,当我们希望获取到它的原始 ref 值时,可以使用 $$()。

我们将上述例子改写为:

diff 复制代码
let count = $ref(0) 
- trackChange(count) 
+ trackChange($$(count))

此时代码可以正常工作,不会再丢失响应性了。

看到这里,聪明的你可能已经意识到了问题:使用响应性语法糖的初衷是为了免去到处写 .value 的麻烦,结果现在新引入了 $ref()、$()、$(),各自还有不同的使用场景,不是更麻烦了吗?

废弃原因

最终,在收集了大量来自社区的反馈后,经过 Vue 核心团队全员投票,决定移除这一特性。在 Vue 3.3 版本中使用会报 warning,从 3.4 版本开始正式移除。

尤雨溪本人也在 github 上发表了决定将响应性语法糖移除的根本原因,链接:github.com/vuejs/rfcs/...

原文是英语,担心有小伙伴可能看不懂,在这里简单翻译一下:

响应性语法糖的初衷是提供一些简练的语法提升开发体验。我们将它作为实验特性发布并在真实场景的使用中获得反馈。尽管它有一些好处,但我们还是发现了下列问题:

  • 没有 .value 使得难以辨认响应式变量的读取和设置。这个问题在 SFC 中可能不那么明显,但是在大型项目中会造成心智负担的明显增大,尤其是在 SFC 外也使用此语法时。
  • 因为第一条,一些开发者倾向于只在 SFC 中使用响应性语法糖,这就造成了代码的不一致性以及在不同心智模型间切换的成本。这是一个进退两难的窘境:只在 SFC 中使用会造成不一致性,而在 SFC 之外使用则会降低可维护性。
  • 既然总有外部函数会使用原始 ref,那么在响应性语法糖与原始 ref 之间的转换是不可避免的。这就产生了另一个需要学习的东西以及额外的认知负担,并且我们发现这会比纯粹的组合式 API 更让初学者感到困惑。

最重要的是,响应性语法糖会带来代码风格分裂的潜在危险。尽管这一功能是自愿使用的,一些使用者还是强烈反对该提议,因为他们不想维护用了语法糖和没用两种风格的代码。这确实值得担心因为使用响应性语法糖需要的心智模型违背了 JavaScript 的基本语义(对变量赋值会触发响应式副作用)。

在考虑了所有因素之后,我们认为将它发布为一个稳定功能带来的问题会大于收益。

结语

在 Vue3 发布之初,Vue 核心团队就考虑到了 ref 需要到处使用 .value 的繁琐,推出了响应性语法糖试图解决这一问题。

响应性语法糖提供了一系列编译器宏,让开发者在书写代码时不必使用 .value,而是在编译阶段由编译器自动加上。

最终,出于代码风格一致性和可维护性上的考量,这一特性最终在 Vue 3.4 版本被正式废弃。

相关推荐
todoitbo4 分钟前
本来只想给内网开个口子,Natapp 却多给了一道防护
前端·javascript·vue.js·内网穿透·网络防护·natapp
会灭火的程序员9 分钟前
SuperMap AgentX Server智能体接入WEB应用技术文档
前端·supermap·agentx·agentx server
CRMEB14 分钟前
商品 SKU 设计,从简单规格到多规格踩过什么
java·前端·数据库·开源
Chloe.Zz15 分钟前
一篇入门Agent
开发语言·前端·javascript
java1234_小锋27 分钟前
【技术专题】HTML5 网页技术 - HTML5 表格标签
前端·html·html5
雪芽蓝域zzs36 分钟前
JS 项目转 TS 项目(Vue3 + 若依这类后台项目)完整改造清单
前端·vue.js
定栓1 小时前
Webpack迁到Vite第四节:SVG 图标系统
前端·webpack·node.js
Dovis(誓平步青云)1 小时前
车辆进入隧道后信号断开,座舱旅程怎样补回事件
java·开发语言·前端·数据库·电脑
定栓1 小时前
Webpack迁到Vite第六节:构建配置详解(vite.config.js)
前端·javascript·webpack