浅析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监测不到了。只有全量替换对象的值才能触发响应式更新

posted @ 2023-07-17 21:58  古兰精  阅读(1548)  评论(0编辑  收藏  举报