vue3学习--readonly与shallowReadonly、toRaw与markRaw、toRef的特点与作用

1,981 阅读2分钟

这是我参与更文挑战的第26天,活动详情查看: 更文挑战

一、readonly与shallowReadonly

readonly深度只读数据,传入响应式或纯对象,返回一个原始对象的只读代理,对象内部任何嵌套的属性也是只读的,在某些特定的情况下,不希望对数据进行更新操作,那就可以包装生产一个只读代理对象来读取数据,防止对数据的修改或删除等操作。 shallowReadonly浅只读数据,传入响应式或纯对象,返回一个原始对象的只读代理,但是这个只读只是第一层只读,非深度只读。

下面代码中,使用readonly包裹的数据,深层都是只读的,shallowReadonly只有最外面那层才是只读的

<template>
  <div></div>
</template>

<script lang="ts">
import { defineComponent, readonly, shallowReadonly } from "vue";

export default defineComponent({
  name: "",
  setup() {
    // readonly 深层只读
    let deepObj = readonly({
      a: 0,
      b: {
        c: 0,
      },
    });
    let changeDeepObj = () => {
        deepObj.b.c++
    }

    // shallowReadonly 浅层只读
    let shallowObj = shallowReadonly({
      a: 0,
      b: {
        c: 0,
      },
    });
    let changeShallowObj = () => {
        shallowObj.b.c++
    }
    return {
        deepObj,
        changeDeepObj,
        shallowObj,
        changeShallowObj
    }
  },
});
</script>

<style scoped>
</style>

image.png

二、toRaw与markRaw

toRaw可以将由reactive或readonly函数转换成响应式代理的普通对象,对普通对象的属性值进行修改,就不会更新视图界面。一般用于渲染具有不可变数据源的大列表,跳过代理转换可以提高性能。

markRaw标记一个对象,使其永远不会转换为响应式数据,只能返回这个对象本身,一般用于某些值不该被设置为响应式的,比如第三方类实例或vue对象等场景。

下面代码,使用toRaw后,响应式的数据变为不是响应式了

<template>
  <div>
      <p>姓名: {{rawObjA.name}} 数量: {{rawObjA.count}}   <button @click="changeRawObjA">改变rawObjA方法</button></p>
  </div>
</template>

<script lang="ts">
import { defineComponent, toRaw, markRaw , reactive } from 'vue';

export default defineComponent({
  name: 'raw',
  setup() {
      // 定义一个响应式数据
      let reactiveObjA = {
          name: '张三',
          count: 1
      }

      // 使用toRaw转换响应式数据为不响应式数据
      let rawObjA = toRaw(reactiveObjA)

      // 改变rawObjA方法
      let changeRawObjA = () =>  {
          rawObjA.count++
          console.log(rawObjA.count);
      }

      return {
          rawObjA,
          changeRawObjA
      }
  }
});
</script>

<style scoped>

</style>

2021-06-27-15-42-26.gif

markRaw标记一个永远不是响应式的数据, 哪怕后面用reactive转也是不响应式的

<p>姓名: {{markRawObjB.name}} 数量: {{markRawObjB.count}}   <button @click="changeReactiveMarkRawB">改变rawObjA方法</button></p>

  // 改变rawObjA方法
      let changeRawObjA = () =>  {
          rawObjA.count++
          console.log(rawObjA.count);
      }

      // 2. markRaw 是标记一个数据永远是不响应式的
      let markRawObjB = {
          name: '王五',
          count: 1

2021-06-27-15-48-59.gif

三、toRef的特点与作用

toRef为响应式对象上的某个属性创建一个Ref引用,更新时引用对象会同步更新,注意如果通过toRef创建的数据修改时,并不会触发视图界面的更新,因为toRef的本质是引用,与原始数据有关联。

从一个对象中拿出一个属性,操作这个属性,这个属性并不是响应式的

<template>
  <div>
      <p>{{objA.count}} <button @click="changeObjA">改变objA的方法</button> </p>
  </div>
</template>

<script lang="ts">
import { defineComponent,toRef,reactive } from 'vue';

export default defineComponent({
  name: '',
  setup() {
      let objA = reactive({
          count: 0
      }) 

      let changeObjA = () => {
          let count = objA.count
          count++ 
      }

      return {
          objA,
          changeObjA
      }
  }
});
</script>

<style scoped>

</style>

2021-06-27-16-12-48.gif

使用toRef使其成为响应式

  let count =toRef(objA,'count')
          count.value++ 

2021-06-27-16-15-11.gif