vue3中的Reactive和ref相关api

132 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第11天,点击查看活动详情

一、Reactive API

reactive API对传入的类型是有限制的,它要求我们必须传入的是一个对象或者数组类型

1、Reactive判断api isProxy:判断对象是否由reactive或者readonly创建的对象。

//判断reactive
    const info = reactive({ name: "zhs", age: 23 });
    console.log(isProxy(info))  //true//判断readonly
  const info = readonly({ name: "zhs", age: 20 });
    console.log(isProxy(info))  //true
1234567

isReactive:检查对象是否是reactive创建的响应式代理,如果该代理是 readonly 建的,但包裹了由 reactive 创建的另一个代理,它也会返回 true

    const info = reactive({ name: "zhs", age: 23 });
    console.log(isReactive(info))   //true//即使在readonly外层包裹reactive也是可以的。
    const info = reactive({ name: "zhs", age: 23 });
    console.log(isReactive(info))   //true
//其代理为readonly创建的,但是其内部为reactive创建的,打印结果为true,反之为false.
    const info = reactive({name:"zs"})
    const set = readonly(info)
    console.log(isReactive(set))   //true

isReadonly:检查对象是否由readonly创建的只读代理

    const info = readonly({name:"zhs"})
    console.log(isReadonly(info))   //true
12

toRaw:返回reactive和readonly代理的原始对象(建议保留对原始对象的持久引用。请谨慎使用)

    const info = readonly({name:"zhs"})
    console.log(toRaw(info))    // {name:"zs"}
12

shallowReactive:创建一个响应式代理,它跟踪其自身 property 的响应性,但不执行嵌套对象的深层响应式转换 (深层还是原生对象)

   let info = shallowReactive({ info: { counter: 1 }, age: 20 });
   当我们改变age的值时,页面会进行重新渲染,当我们改变counter的值时,不会进行页面的重新渲染。
12

shallowReadonly:创建一个 proxy,只进行对象浅层次的只读设置,使其自身的 property 为只读,深层次仍然是原生对象,(深层还是可读、可写的)。

    const info = shallowReadonly(
    {
      baseInfo: { name: "zhs", age: 23 },
      scores: 100,
    });
如上面代码所示,此时改变scores的值会报出warning,当改变baseInfo中的age值时,页面不会
发生更新,因为此时baseInfo中的对象是普通对象,而不是响应式对象。

二、ref相关api

在setup中如何使用ref或者元素或者组件?

要定义一个ref对象,绑定到元素或者组件的ref属性上即可:

<template>
  <div>
      <h2 ref="h2Ref" />
  </div>
</template>
<script>
import { ref } from 'vue'
export default {
  setup(){
    const h2Ref = ref(null)
    return {
      h2Ref
    }
  }
}
</script>

如果我们使用ES6的解构语法,对reactive返回的对象进行解构获取值,那么之后无论是修改结构后的变量,还是修改reactive

返回的state对象数据都不再是响应式的:可以使用toRefs:可以将reactive返回的对象中的属性都转成ref;

toRefs

    let info = reactive({ name: "zhs", age: 23 });
    return {
    ...info
  }
1234

此时我们使用reactive来设置响应式对象时,此时返回的解构对象不是响应式的,我们可以使用toRefs来解决。

  let info = reactive({name:"zhs", age:23})
  return {
      ...toRefs(info)
    } 
    此时就相当于对info解构后的内容进行设置ref响应式
import { reactive, toRef } from "vue";
export default {
  setup() {
    const info = reactive({ name: "zhs", age: 23 });
    let age = toRef(info, "age") 
    //toRef第一个参数是reactive对象,第二个参数是属性
    //表示从该响应式对象中取出age属性并将其转化为ref对象
    let {name} = info
    const changeAge = () => {
      age.value++   //age为ref对象
    };
    const changeName = () => {
      name= "dddd";   //这里不加value,因为其不是ref对象
    }; 
​
    return {
      age,
      name,
      changeName,
      changeAge,
    };
  },
};

2. ref的其他api

unref:将取出ref中的value值,如果参数是一个 ref,则返回内部值,否则返回参数本身;

      const age = ref(20)
      console.log(age.value)   //20  
      console.log(unref(age))  //20
      //其内部可以表示为:
      //这是 val = isRef(val) ? val.value : val 的语法糖函数;

isRef:判断一个对象是否是一个ref对象

      const age = ref(20)
      console.log(isRef(age))   //true

shallowRef:创建浅层的ref对象

import { ref } from 'vue'
  export default {
    setup() {
      const info = ref({name:"sx", age:2})
      const changeAge = () => {
        info.value.age++
      }
      return {
        info,
        changeAge
      }
    }
  }
  此时当改变age中的值时,会发生页面的改变。
import { ref, shallowRef } from 'vue'
  export default {
    setup() {
      const info = shallowRef({name:"sx", age:2})
      const changeAge = () => {
        info.value.age++
        console.log(info.value)
      }
      return {
        info,
        changeAge
      }
    }
  }
此时当改变age的值时,不会发生页面的改变。

triggerRef: 手动触发和shallowRef相关联的副作用。

import { ref, shallowRef, triggerRef } from 'vue'
  export default {
    setup() {
      const info = shallowRef({name:"sx", age:2})
      const changeAge = () => {
        info.value.age++
        console.log(info.value)
        triggerRef(info)   //加上triggerRef就能改变页面中的内容
      }
      return {
        info,
        changeAge
      }
    }
  }

customRef: 创建一个自定义的ref,并对其依赖项跟踪和更新触发进行显示控制

  1. 它需要一个工厂函数,该函数接受 track 和 trigger 函数作为参数;
  1. 并且应该返回一个带有 get 和 set 的对象;
  2. 一般来说,track() 应该在 get() 方法中调用,而 trigger() 应该在 set() 中调用。然而事实上,你对何时调用、是否应该调用他们有完全的控制权。

案例:双向绑定的属性进行防抖 ref 的操作,即只在最近一次 set 调用后的一段固定间隔后再调用:

import { customRef } from "vue"
export function useDebouncedRef(value, delay = 200) {
  let timeout
  return customRef((track, trigger) => {
    return {
      get() {
        track()
        return value
      },
      set(newValue) {
        clearTimeout(timeout)
        timeout = setTimeout(() => {
          value = newValue
          trigger()
        }, delay)
      }
    }
  })
}

在组件中使用

<script setup>
import { useDebouncedRef } from './debouncedRef'
const text = useDebouncedRef('hello')
</script><template>
  <input v-model="text" />
</template>