vue3的shallowRef和shallowReactive

reactive用来包装一个对象,使其每个对象属性都具有响应性,但是这个包装过程是递归调用的,如果包装的对象有过多属性而又不需要设置相应,无疑是性能浪费

针对这种情况vue设置了shallowReactive shallowRef两个方法来包装响应式数据,通过该方法包装的数据只有第一层具有响应性

shallowReactive

reactive一样,该方法只能把对象或数组包装为响应式对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<div class="about">
{{ test }}
<button @click="change">change</button>
</div>
</template>
<script setup>
const test = shallowReactive({
a: {
b: "b",
},
});

function change() {
test.a.b = "new";
console.log(test);
}
</script>

通过change方法改变了test的深层属性,这时会发现控制台中打印的数据是改变后的,而浏览器视图中仍然是原来的对象,而如果把change改成修改test的第一层属性,则会触发视图的更新

1
2
3
4
function change() {
test.a = "new";
console.log(test);
}

shallowRef

该方法就可以包装对象和基础类型的数据了,不过包装基础属性的数据和普通的ref没有区别,这里就只说说包装对象时的用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<div class="about">
{{ test }}
<button @click="change">change</button>
</div>
</template>
<script setup>
const test = shallowRef({
a: "a",
});

function change() {
test.value.a = "new";
console.log(test.value);
}
</script>

shallowReactive不同,这里修改了对象的第一层属性不会触发视图更新,shallowRef的第一层数据实际指的是包装的整个数据,所以改成这样

1
2
3
4
function change() {
test.value = { b: "b" };
console.log(test.value);
}

vue就会响应数据的更新了

triggerRef

shallowRef数据被改变后如果要同步到视图上,可以调用一次triggerRef函数,该函数接收shallowRef数据,并会把该数据同步到视图上

1
2
3
4
5
6
7
8
9
10
11
const test = shallowRef({
a: "A",
b: "B",
});

function change() {
test.value.a = "new";
triggerRef(test);
test.value.b = "new";
}
复制代码

通过调用一次该方法,两个数据都会被同步

总结:

可以在通过ref获得dom元素时使用来去掉不必要的监听,节省性能