shallowReactive 与 shallowRef(浅拷贝)

  1. shallowReactive : 只处理了对象内最外层属性的响应式(也就是浅响应式)
  2. shallowRef: 只处理了value的响应式, 不进行对象的reactive处理
  3. 什么时候用浅响应式呢?
  • 一般情况下使用ref和reactive即可
  • 如果有一个对象数据, 结构比较深, 但变化时只是外层属性变化 ===> shallowReactive
  • 如果有一个对象数据, 后面会产生新的对象来替换 ===> shallowRef
<template>
  <h1>shallowReactive 与 shallowRef</h1>
  <h2>{{m1}}</h2>
  <h2>{{m2}}</h2>
  <h2>{{m3}}</h2>
  <h2>{{m4}}</h2>
  <hr>
  <button @click="updata">点击</button>


</template>

<script lang="ts">

import {onMounted, reactive, shallowReactive, ref, toRefs, shallowRef} from "vue";

export default ({
  name:'App',
  setup(){
    // 深度劫持(响应)
    const m1=reactive({
      name:'jack',
      agr:20,
      car:{
        name:'宝马',
        color:'red'
      }
    })
    // 浅度劫持(响应)
    const m2=shallowReactive ({
      name:'jack',
      agr:20,
      car:{
        name:'宝马',
        color:'red'
      }
    })
    const m3=ref({
      name:'jack',
      agr:20,
      car:{
        name:'宝马',
        color:'red'
      }
    }) // ref传对象时,里面会进行reactive处理
    const m4=shallowRef({
      name:'jack',
      agr:20,
      car:{
        name:'宝马',
        color:'red'
      }
    })
    const updata = () => {
      // m1.name +="=="
      // m1.car.name +="==" // 两个都能执行说明是深度响应
      // m2.name +="=="
      // m2.car.name +="==" // 第二个不都能执行说明是浅度响应,对浅层数据能够进行修改
      // m3.value.name +="=="
      // m3.value.car.name +="==" // 两个都能执行说明是深度响应
      // m4.value.name +="=="
      // m4.value.car.name +="==" // 两个都不都能执行说明是浅度响应 m4类型是Object,不能进行响应式操作(数据不能修改)
    }
    return{
      m1,m2,m3,m4,updata,
    }
  }

})
</script>

readonly 与 shallowReadonly

  1. readonly:深度只读数据
  2. 获取一个对象 (响应式或纯对象) 或 ref 并返回原始代理的只读代理
  3. 只读代理是深层的:访问的任何嵌套 property 也是只读的。
  4. shallowReadonly:浅只读数据
  5. 浅只读数据创建一个代理,使其自身的 property 为只读,但不执行嵌套对象的深度只读转换
  6. 应用场景:在某些特定情况下, 我们可能不希望对数据进行更新的操作, 那就可以包装生成一个只读代理对象来读取数据, 而不能修改或删除
<template>
  <h1>shallowReactive 与 shallowRef</h1>
  <h2>{{m2}}</h2>
  <h1>{{m3}}</h1>
  <hr>
  <button @click="updata">点击</button>


</template>

<script lang="ts">

import {reactive,readonly,shallowReadonly} from "vue";

export default ({
  name:'App',
  setup() {
    const m1 = reactive({
      name: 'jack',
      agr: 20,
      car: {
        name: '宝马',
        color: 'red'
      }
    })
    const m2=readonly(m1)
    const m3=shallowReadonly(m1)
    const updata = () => {
      // m2.name+='=='
      // m2.car.name+='=='
      // m3.name+='=='
      m3.car.name+='=='
      /*
      * readonly的只读是深层次的,所有数据都不能修改
      * shallowReadonly的只读是浅层次的,里面的数据是可以修改的
      */
    }
    return{
      m2,m3,updata,
    }
  }

})
</script>

toRaw 与 markRaw

  1. toRaw返回由 reactive 或 readonly 方法转换成响应式代理的普通对象
  2. 这是一个还原方法,可用于临时读取,访问不会被代理/跟踪,写入时也不会触发界面更新
  3. markRaw标记一个对象,使其永远不会转换为代理。返回对象本身
  4. 应用场景:
    有些值不应被设置为响应式的,例如复杂的第三方类实例或 Vue 组件对象
    当渲染具有不可变数据源的大列表时,跳过代理转换可以提高性能
<template>
  <h1>toRaw 与 markRaw</h1>
  <h2>{{m1}}</h2>
  <hr>
  <button @click="clicktoRaw">点击 toRaw </button>
  <button @click="clickmarkRaw">点击 markRaw </button>


</template>

<script lang="ts">

import {reactive,toRaw,markRaw} from "vue";
interface IPerson{
  name:String,
  age:Number,
  car?:String[]
}
export default ({
  name:'App',
  setup() {

    const m1 = reactive<IPerson>({
      name: 'jack',
      age: 20,
    })
    const clicktoRaw = () => {
      const user=toRaw(m1)
      user.name+="==" // 点击时不会发生反应,因为转化为了普通对象
    }
    const clickmarkRaw = () => {
      // m1.car=['宝马', 'red']
      // m1.car[0]+='==' // 点击时可以更改,说明添加操作让其转化为Proxy代理
      const car=['宝马', 'red']
      m1.car=markRaw(car)
      // markRaw处理后就不能成为代理对象了
      setTimeout(() => {
       if(m1.car){
         m1.car[0] += '=='
         console.log('执行中')
       }
      }, 1000)
    }
    return {
      m1,clickmarkRaw,clicktoRaw
    }

  }

})
</script>

toRef

  1. 为源响应式对象上的某个属性创建一个 ref对象, 二者内部操作的是同一个数据值, 更新时二者是同步的
  2. 区别ref: 拷贝了一份新的数据值单独操作, 更新时相互不影响
  3. 应用: 当要将 某个prop 的 ref 传递给复合函数时,toRef 很有用
<template>
  <h1>clicktoRef</h1>
  <h2>{{m1}}</h2>
  <hr>
  <button @click="clicktoRef">点击 clicktoRef </button>
</template>

<script lang="ts">
import {reactive, ref, toRef,} from "vue";
export default ({
  name:'App',
  setup() {
    const m1 = reactive({
      name: 'jack',
      age: 20,
    })
    // 把响应式数据m1 中name 属性变成ref对象
    const name=toRef(m1,'name')
    // 把响应时数据进行包装变成ref对象
    const age=ref(m1.age)
    const clicktoRef = () => {
      console.log('测试')
      // m1.name +='=='
      // name.value +='==' // 两个都会改变
     
      // m1.age +=2
      age.value +=2 // 第二个不会改变,说明ref拷贝后的值互不影响
    }

    return {
      m1,clicktoRef
    }

  }

})
</script>

customRef

  1. 创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制
  2. 自定义hook函数防抖
<template>
  <h1>customRef</h1>
 <input type="text" v-model="keyword">
  <h3>{{keyword}}</h3>



</template>

<script lang="ts">

import {customRef, reactive, ref, toRef,} from "vue";
// 自定义防抖函数
// value传入数据不确定用泛型,time防抖时间
function useAntiShake<T>(val:T,delay=500){
  let timeOutId: number // 准备一个存储定时器ID变量
  return customRef((track,trigger)=>{
    return{
      // 返回数据的
      get(){
        // 告诉VUE追踪数据
        track()
        return val
      },
      set(newVal:T){
        // 清理定时器
        clearTimeout(timeOutId)
        // 开启定时器
        timeOutId=setTimeout(()=>{
          val=newVal
          trigger()
        },delay)
      }
    }
  })
}
export default ({
  name:'App',
  setup() {
    // const keyword=ref('1')
    const keyword=useAntiShake('123',1000)
    return {
      keyword
    }

  }

})
</script>

provide 与 inject

  1. provide和inject提供依赖注入,功能类似 2.x 的provide/inject
  2. 实现跨层级组件(祖孙)间通信
  • app.vue
<template>
  <h1>provide 与 inject</h1>
  <h2>{{color}}</h2>
  <button @click="color='red'">点击</button>
  <button @click="color='yellow'">点击</button>
  <button @click="color='pink'">点击</button>

  <hr>
  <son></son>


</template>

<script lang="ts">

import {reactive, ref, defineComponent, provide} from "vue";
import son from './components/son.vue'
export default defineComponent({
  name:'App',
  components:{
    son,
  },
  setup() {
   const color=ref('red')
    provide('color',color)
    return {
      color
    }

  }

})
</script>
  • son.vue
<template>
  <h2>son组件</h2>
  <hr>
  <grandson></grandson>
</template>

<script>
import grandson from "./grandSon.vue";
export default {
  name: "son",
  components: {
    grandson
  }
}
</script>

<style scoped>

</style>
  • grandson.vue
<template>
  <h2 :style="{color}">grandson组件</h2>
</template>
<script>
import {inject} from "vue";
export default {
  name: "grandSon",
  setup(){
    const color=inject('color')
    return{
      color,
    }
  }
}
</script>
<style scoped>
</style>

响应式数据的判断

  1. isRef: 检查一个值是否为一个 ref 对象
  2. isReactive: 检查一个对象是否是由 reactive 创建的响应式代理
  3. isReadonly: 检查一个对象是否是由 readonly 创建的只读代理
  4. isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理
Logo

前往低代码交流专区

更多推荐