自从用vuepress 2开发OpenAPI平台百家饭以来,按照官方指引,我们一直使用ref函数,在composition api里面创建变量引用。后来陆续了解到shadowref,reactive,shadowreactive函数,就有点分不清楚了,今天争取一篇文章分清楚这几个函数的区别。
包含子属性 | 可传入一般类型 | 子属性引用类型 | |
ref | 包含 | 能 | 统一引用,所有属性共享一个响应对象(一个属性变动,所有用到该应用属性的地方都要更新) |
shadowRef | 不包含 | 能 | 统一引用,所有属性共享一个响应对象(一个属性变动,所有用到该应用属性的地方都要更新) |
reactive | 包含 | 不能,只接受objarray | 分别引用,每个属性是一个独立的reactive对象 |
shadowReactive | 不包含 | 不能,只接受objarray | 分别引用,每个属性是一个独立的reactive对象 |
通常情况下,可以无脑使用ref
查询了多篇文章之后,一个结论是,大部分情况下都可以使用ref,这是vue3最通常的一种响应式用法。如果ref用于object,object会调用toReactive转变为reactive对象,所以,内部实际上仍然是reactive的复用。
同时,因为ref的所有对象都会附加.value操作,使用ref会有更好的代码阅读性。
而相对,主用reactive会使得引用对象和普通对象无法区分,而且reactive无法使用到普通类型变量的问题,使得使用会更为复杂。
使用reactive更好的情况
当然,你觉得不用.value更清爽,用reactive也是可以。
如果不会重新对ref或reactive后的变量重新赋值,可以使用reactive,但是如果要重新赋值,reactive不适用。例如下面的例子是不行的,界面不会更新。
const testValue = reactive({
value:2,
})
function testA() {
testValue = {
value:5,
}
}
<template>
<button @click="testA">+</button>
<div>
{{ testValue }}
</div>
</template>
一篇文章提到只有一种情况使用reactive更好,因为reactive创建的引用是针对每个属性独立的,因此,如果一个对象中每个属性对应的响应显示不同,那么,我们可以使用reactive提升性能,因为reactive创建的是一个属性一个引用,那就可以避免因为属性A变化去刷新用到属性B的地方(这个说法我没有测试出来,待验证)
不会涉及嵌套对象的情况,可以使用shadow版本的Ref或者Reactive提升性能
ref和reactive是遍历子属性,深度进行响应式的,如果不需要的时候,可以使用shadowRef或者shadowReactive
并不是所有数据都需要用到ref
这是一个很意外的结论,自从知道vue3要定义响应式数据之后,所有渲染中要用到的数据,我都是使用ref定义的,但是搞清楚这些函数区别的过程中,我发现并不是这样,只有需要改变数据时有刷新界面需要的地方才需要,也就是响应式三个字的含义。
那你可能说,难道有需要在渲染中用到的不用刷新的数据?
还真有,比如:
<script setup>
//setup:
var detailValue = 4;
const showDetail = ref(false);
function show() {
detailValue++;
showDetail.value = !showDetail.value
}
</script>
<template>
<div v-if="showDetail">
{{ detailValue }}
</div>
</template>
这种情况应该是很常见的情况吧,我们通常需要使用一个v-if来控制显示与否,里面显示详细数据,经测试,里面的显示详情并不需要响应式数据,每次v-if成立的时候,会获取最新值进行显示。另外,经测试,v-show有同样的效果,虽然v-show控制display属性,但其内容也是每次都刷新的,即便v-show为false的情况。