浅析vue3中如何使用动态组件、如何快速理解Vue3的toRaw和markRaw、ref与shallowRef、shallowReactive区别
一、Vue3中使用 component :is 加载动态组件
1、不使用setup语法糖,这种方式和vue2差不多,is可以是个字符串
2、使用setup语法糖,这时候的is如果使用字符串就会加载不出来,得使用组件实例
<component class="task-box" :is="componentObj[route.params.type]" :info="taskInfo"></component>
import DeliverDetailTeach from './components/DeliverDetailTeach.vue'
// ...
const componentObj = {
1: markRaw(DeliverDetailTeach),
2: markRaw(DeliverDetailLive),
}
3、问题:为什么 vue3 需要对引入的组件使用 markRow?
vue2中 is 是通过组件名称切换的,vue3中setup是通过组件实例切换的。直接把组件实例放到 reactive 中代理,vue会发出警告。告知我们可以通过 shallowRef 或者 markRaw 跳过proxy 代理。对组件实例进行响应式代理毫无意义,且浪费性能。
markRow:标记一个对象,使其不能成为一个响应式对象
toRaw:将响应式对象(由 reactive 定义的响应式)转换为普通对象
shallowRef:只处理基本数据类型的响应式, 不进行对象的响应式处理
shallowReactive:只处理对象最外层属性的响应式(浅响应式)
二、toRaw和markRaw
1、raw 的意思
- raw就是原始的意思
toRaw
就是把一个响应式对象转化为普通对象markRaw
就是把某个数据,标记为普通对象,当我们把它放到响应式对象中,也依然是非响应式的
2、toRaw 的作用是什么
- 将一个用reactive生成的响应式对象,变成非响应式的普通对象
- 然后赋值给新的变量
- 注意:不影响原来的对象
3、toRaw 的使用场景是什么
- 用于读取响应式对象中的普通对象
- 对这个对象的所有操作,都不会引起页面更新
4、为什么需要用到 markRaw
(1)有些值不应被设置为响应式的,例如复杂的第三方库
- 比如一个响应式对象中,要放入axios,或者别的随机数字的第三方库
- 如果不让他变成非响应式的,那么Vue就会去找到每一个层级,让其都能响应式处理
- 这样的情况下,性能就会受到严重影响
- 所以我们需要让其变成永远都不会成功响应式的数据,提高性能
(2)当渲染具有不可变数据源的大列表时,跳过响应式可以提高性能
5、对谁使用markRaw?
这个数据原本不能是响应式的;然后把这个数据放到响应式对象当中,这个属性依然不是响应式的
三、ref与shallowRef区别
1、ref 很容易理解,使用ref创建的对象,里面任意深度的属性与视图都是响应性的
2、shallowRef
先说说shallowRef的特点:与ref不同,shallowRef修改深层属性时,并不会更新视图
<template>
<div>
<p>{{data.foo}}</p>
<button @click="update">update</button>
<button @click="log">log</button>
</div>
</template>
setup() {
const data = shallowRef({
foo: '1'
})
function update() {
data.value.foo = '2'
}
function log() {
console.log(data.value.foo)
}
return {
data,
}
}
上例点击update时,视图并不会更新,但是点击log按钮时,打印出foo的值为2。想要更新视图,必须给value赋值,直接替换整个对象。修改update方法
function update() {
data.value = { foo: 200 }
}
再次点击update按钮,视图更新
shalow即浅的意思,shallowRef 只有整个数据变更时才刷新视图,或者在修改了数据之后,调用triggerRef方法,主动触发视图刷新
function update() {
data.value.foo = '300';
triggerRef(data); // 触发视图刷新
}
3、为什么要使用shallowRef
因为ref方法会递归遍历对象的所有属性,使所有属性都具备响应性,所以,当对象很复杂且庞大时,过多的监听会导致性能上的损耗。如假设有一个文章列表数组:
list = [
{ title: '', auto: '', time: '' },
{ title: '', auto: '', time: '' },
{ title: '', auto: '', time: '' },
//...
]
像这种做展示用的数据,并不需要每个属性都做响应性,此时使用shallowRef就很合适
4、shallowReactive 与 shallowRef
shallowReactive:只处理对象最外层属性的响应式(浅响应式)
shallowRef:只处理基本数据类型的响应式,不进行对象的响应式处理
5、什么时候使用?
(1)如果有一个对象数据,结构比较深,但变化时只是外层属性变化 > 使用shallowReactive
我们修改数据只有定义在对象第一层的属性才是响应式的,深层次的数据将不再具有响应式的功能,因为深层次的数据将不再是一个响应式对象,而是一给普通对象(数据变了,但是vue监测不到,是无法触发页面更新的)
(2)如果有一个对象数据,后续功能不会修改该对象中的属性,而是生新的对象来替换 > shallowRef
我们调用了shallowRef方法传递了基本数据类型,我们可以看到,当前属性是有响应式的。当我们点击修改数据,在页面中可以看到是有响应式功能的
但是当传递的是一个对象的时候,我们可以看到,传递的对象将变成一个普通对象,不再具有响应式功能了。修改对象的属性数据后将不在触发页面的更新,因为vue监测不到了。只有全量替换对象的值才能触发响应式更新