6

Vue3中 响应式 API ( readonly、shallowReadonly、toRaw、markRaw ) 详解

 1 year ago
source link: https://blog.51cto.com/u_15302032/5762480
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

1. readonly 函数

接受一个对象 (不论是响应式还是普通的) 或是一个 ref,返回一个原值的只读代理。
只读代理是深层的:对任何嵌套属性的访问都将是只读的。它的 ref 解包行为与 reactive() 相同,但解包得到的值是只读的。
要避免深层级的转换行为,请使用 shallowReadonly() 作替代。

<template>
  <div>
    <div>
      {{count}}
      <button @click="changeCount">changeCount</button>
    </div>
    <div>
      {{obj1.name}} {{obj1.info.age}}
      <button @click="obj1Age">obj1Age</button>
    </div>
  </div>
</template>

<script>
import { reactive,readonly, ref } from 'vue';
export default {
  setup(){
    let count = ref(0);
    let obj1 = reactive({
      name:'张三',
      info:{
        age:18
      }
    })
    count = readonly(count);
    obj1 = readonly(obj1);

    const changeCount = () => {
      count.value++;
      console.log(count)
    }
    const obj1Age = () => {
      obj1.name = '李四';
      obj1.info.age++;
      console.log(obj1)
    }
    return {
      count,
      changeCount,
      obj1,
      obj1Age,
    }
  } 
}
</script>

分别触发 changeCount、obj1Age 一次

Vue3中 响应式 API ( readonly、shallowReadonly、toRaw、markRaw ) 详解_Vue3.x

2. shallowReadonly 函数

readonly() 的浅层作用形式
和 readonly() 不同,这里没有深层级的转换:只有根层级的属性变为了只读。属性的值都会被原样存储和暴露,这也意味着值为 ref 的属性不会被自动解包了。

Vue3中 响应式 API ( readonly、shallowReadonly、toRaw、markRaw ) 详解_javascript_02
<template>
  <div>
    <div>
      {{count}}
      <button @click="changeCount">changeCount</button>
    </div>
    <div>
      {{obj1.name}} {{obj1.info.age}}
      <button @click="obj1Age">obj1Age</button>
    </div>
  </div>
</template>

<script>
import { reactive,shallowReadonly, ref } from 'vue';
export default {
  setup(){
    let count = ref(0);
    let obj1 = reactive({
      name:'张三',
      info:{
        age:18
      }
    })
    count = shallowReadonly(count);
    obj1 = shallowReadonly(obj1);

    const changeCount = () => {
      count.value++;
      console.log(count)
    }
    const obj1Age = () => {
      obj1.name = '李四';
      obj1.info.age++;
      console.log(obj1)
    }
    return {
      count,
      changeCount,
      obj1,
      obj1Age,
    }
  } 
}
</script>

分别触发 changeCount、obj1Age 一次

Vue3中 响应式 API ( readonly、shallowReadonly、toRaw、markRaw ) 详解_Vue3.x_03

3. toRaw 函数

根据一个 Vue 创建的代理返回其原始对象。
toRaw() 可以返回由 reactive()、readonly()、shallowReactive() 或者 shallowReadonly() 创建的代理对应的原始对象。
这是一个可以用于临时读取而不引起代理访问/跟踪开销,或是写入而不触发更改的特殊方法。不建议保存对原始对象的持久引用,请谨慎使用。

<template>
  <div>
    <div>
      {{obj.name}} {{obj.info.age}}
      <button @click="objToRaw">objToRaw</button>
    </div>
  </div>
</template>

<script>
import { reactive,toRaw } from 'vue';
export default {
  setup(){
    let obj = reactive({
      name:'张三',
      info:{
        age:18
      }
    })
    const objToRaw = () => {
      let objRaw = toRaw(obj)
      objRaw.info.age++
      console.log(obj,objRaw)
    }
    return {
      obj,
      objToRaw,
    }
  } 
}
</script>

触发 objToRaw 两次

Vue3中 响应式 API ( readonly、shallowReadonly、toRaw、markRaw ) 详解_javascript_04

4. markRaw 函数

将一个对象标记为不可被转为代理。返回该对象本身。
作用:标记一个对象,使其永远不会再成为响应式对象;
应用场景:

  • 有些值不应被设置为响应式的,如:复杂的第三方类库等;
  • 当渲染具有不可变数据源的大列表时,跳过响应式转换可提高性能;
Vue3中 响应式 API ( readonly、shallowReadonly、toRaw、markRaw ) 详解_Vue3.x_05
<template>
  <div>
    <div>姓名:{{obj.name}} </div> 
    <div>年龄:{{obj.info.age}} </div> 
    <div v-if="obj.car">座驾:{{obj.car}} </div> 
    <div v-if="obj.address">地址:{{obj.address}} </div> 
    <button @click="updateObj">updateObj</button>
    <button @click="changeAddress">changeAddress</button>
    <button @click="changeCar">changeCar</button>
  </div>
</template>

<script>
import { reactive,markRaw } from 'vue';
export default {
  setup(){
    let obj = reactive({
      name:'张三',
      info:{
        age:18
      }
    })
    const updateObj = () => {
      const address = { province:'湖北',city:'武汉' };
      obj.address = address; // obj 配置了 Proxy 代理,因此捕获到对 obj 任何属性的操作且都是响应式的;
      const car = { brand:'宝马',price:30 };
      obj.car = markRaw(car); // car内部属性值已经改了,只是没有响应式更新。它和readonly不同,readonly是压根不让修改 
    }

    function changeAddress(){
      obj.address.province = '江苏';
      obj.address.city = '南京';
      console.log(obj) 
    }
    
    function changeCar(){
      obj.car.brand = 'BMW',
      obj.car.price+= 1
      console.log(obj)
    };

    return {
      obj,
      updateObj,
      changeCar,
      changeAddress,
    }
  } 
}
</script>

依次触发 updateObj、changeAddress、changeCar 一次,效果如下:
(若先触发 changeCar 再触发 changeAddress ,car 的页面信息会进行更新,因为 address 的改变带动了页面的更新 )

Vue3中 响应式 API ( readonly、shallowReadonly、toRaw、markRaw ) 详解_javascript_06

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK