所属分类:web前端开发
自从引入组合式 API 的概念以来,一个主要的未解决的问题就是 ref
和 reactive
到底用哪个。reactive
存在解构丢失响应性的问题,而 ref
需要到处使用 .value
则感觉很繁琐,并且在没有类型系统的帮助时很容易漏掉 .value
。
例如,下面的计数器:
<template>
<button @click="increment">{{ count }}</button>
</template>
登录后复制
使用 ref
定义 count
变量和 increment
方法:
let count = ref(0)
function increment() {
count.value++
}
登录后复制
而使用响应性语法糖,我们可以像这样书写代码:
let count = $ref(0)
function increment() {
count++
}
登录后复制
$ref()
方法是一个编译时的宏命令,它不是一个真实的、在运行时会调用的方法,而是用作 Vue 编译器的标记,表明最终的 count
变量需要是一个响应式变量。.value
的 ref
。所以上面例子中的代码也会被编译成使用 ref
定义的语法。ref
的响应式 API 都有一个相对应的、以 $
为前缀的宏函数。包括以下这些 API:$()
宏来将现存的 ref
转换为响应式变量。const a = ref(0)
let count = $(a)
count++
console.log(a.value) // 1
登录后复制
$$()
宏来将任何对响应式变量的引用都会保留为对相应 ref
的引用。let count = $ref(0)
console.log(isRef($$(count))) // true
登录后复制
$$()
也适用于已解构的 props
,因为它们也是响应式的变量。编译器会高效地通过 toRef
来做转换:
const { count } = defineProps<{ count: number }>()
passAsRef($$(count))
登录后复制
响应性语法糖是 组合式 API 特有的功能,且必须通过构建步骤使用。
@vitejs/plugin-vue@>=2.0.0
,将应用于 SFC 和 js(x)/ts(x) 文件。// vite.config.js
export default {
plugins: [
vue({
reactivityTransform: true
})
]
}
登录后复制
reactivityTransform
现在是一个插件的顶层选项,而不再是位于 script.refSugar
之中了,因为它不仅仅只对 SFC 起效。如果是 vue-cli
构建,需要 vue-loader@>=17.0.0
,目前仅对 SFC 起效。
// vue.config.js
module.exports = {
chainWebpack: (config) => {
config.module
.rule('vue')
.use('vue-loader')
.tap((options) => {
return {
...options,
reactivityTransform: true
}
})
}
}
登录后复制
如果是 webpack
+ vue-loader
构建,需要 vue-loader@>=17.0.0
,目前仅对 SFC 起效。
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
reactivityTransform: true
}
}
]
}
}
登录后复制
tsconfig.json
文件中添加如下代码, 不然会报错 TS2304: Cannot find name '$ref'.
,虽然不影响使用,但是会影响开发体验:"compilerOptions":{ "types": ["vue/ref-macros"] }
登录后复制
eslintrc.cjs
文件中添加如下代码,不然会提示 ESLint: '$ref' is not defined.(no-undef)
:module.exports = { ...globals: {
$ref: "readonly",
$computed: "readonly",
$shallowRef: "readonly",
$customRef: "readonly",
$toRef: "readonly",
}
};
登录后复制
vue/macros
,这样就不用配置第二和第三步中的 tsconfig.json
和 eslintrc
了。import { $ref } from 'vue/macros'
let count = $ref(0)
登录后复制
响应性语法糖曾经是一个实验性功能,且已被废弃,请阅读废弃原因。
在未来的一个小版本更新中,它将会从 Vue core 中被移除。如需继续使用,请通过 Vue Macros 插件。
尤雨溪在2个星期前(2023 年 2 月 21 日上午 10:05 GMT+8),亲自给出了废弃的原因,翻译如下:
正如你们中的许多人已经知道的那样,我们在团队一致同意的情况下正式放弃了这个 RFC。
理由
Reactivity Transform 的最初目标是通过在处理反应状态时提供更简洁的语法来改善开发人员的体验。我们将其作为实验性产品发布,以收集来自现实世界使用情况的反馈。尽管提出了这些好处,我们还是发现了以下问题:
失去 .value
使得更难分辨正在跟踪的内容以及哪条线触发了反应效果。这个问题在小型 SFC 中并不那么明显,但在大型代码库中,心理开销变得更加明显,特别是如果语法也在 SFC 之外使用。
由于 (1),一些用户选择仅在 SFC 内部使用 Reactivity Transform,这会在不同心智模型之间造成不一致和上下文转换成本。因此,困境在于仅在 SFC 内部使用它会导致不一致,但在 SFC 外部使用它会损害可维护性。
由于仍然会有外部函数期望使用原始引用,因此反应变量和原始引用之间的转换是不可避免的。这最终增加了更多的学习内容和额外的精神负担,我们注意到这比普通的 Composition API 更让初学者感到困惑。
最重要的是,碎片化的潜在风险。尽管这是明确的选择加入,但一些用户对该提议表示强烈反对,原因是他们担心他们将不得不与不同的代码库一起工作,在这些代码库中,有些人选择了使用它,而有些人则没有。这是一个合理的担忧,因为 Reactivity Transform 需要一种不同的心智模型,它会扭曲 JavaScript 语义(变量赋值能够触发反应效果)。
考虑到所有因素,我们认为将其作为一个稳定的功能使用会导致问题多于收益,因此不是一个好的权衡。
迁移计划
留言
ref.value
进行转换的部分?响应式 props
解构呢,它会留下来吗?.value
的人现在尽可能避免使用 ref()
并像以前那样使用 reactive()
?.value
是必要的复杂性。就像任何其他响应式库 xxx.set()
一样。...
推荐学习:《vue.js视频教程》
以上就是注意,Vue响应性语法糖已废弃!的详细内容,更多请关注zzsucai.com其它相关文章!