首页
Preview

【Vue3】理解vue3的各种ref:toRef、toRefs、isRef、unref、shallowRef、proxyRefs等。

在Vue3中,我们有很多与响应性相关的函数,比如toReftoRefsisRefunrefshallowRefproxyRefs等。在实际的开发中,合理地使用这些函数能极大地提高我们的开发效率。本文就一起来看看这些响应性相关的函数的详细用法。

ref()

对于ref,大家并不陌生。我们经常在Vue3中使用它。它的功能是接受一个值并返回一个响应性的对象。我们可以通过.value属性访问和修改这个值。在模板中,我们可以省略.value。比如在下面的代码中,当按钮被点击时,页面上的count数值将会响应式地变化。

<template>
    <div>
        {{ count }}
        <button @click="addCount">+1</button>
    </div>
</template>

<script lang='ts' setup>
import { ref } from "vue"
const count = ref(1)
const addCount = () => {
    count.value++
}
</script>

toRef-- toRef(obj, key)

toRef可以基于一个响应性对象中的属性创建一个响应性的ref。同时,这个ref与原始对象中的属性是同步的。如果原始对象属性的值改变了,ref将会相应地发生变化,反之亦然。这个函数接受两个参数,一个是相应的响应,另一个是属性值,如下所示:

<template>
  <div>
    {{ count.a }}
    {{ a }}
    {{ b }}
    <button @click="addCount">+1</button>
  </div>
</template>

<script lang='ts' setup>
import { ref, toRef } from "vue"
const count = ref({
  a: 1,
  b: 2
})
const a = toRef(count.value, 'a')
const b = toRef(count.value, 'b')
const addCount = () => {
  a.value++
}
</script>

当你点击按钮来修改a的值,也就是count中的a也会改变。

toRefs

toRefs可以将一个响应性的对象转换为一个普通的对象,这个普通对象的每一个属性都是一个响应性的ref

<template>
  <div>
    {{ count.a }}
    {{ countAsRefs.a }}
    {{ countAsRefs.b }}
    <button @click="addCount">+1</button>
  </div>
</template>

<script lang='ts' setup>
import { reactive, toRefs } from "vue"
const count = reactive({
  a: 1,
  b: 2
})
const countAsRefs = toRefs(count)
const addCount = () => {
  countAsRefs.a.value++
}
</script>

在这种情况下,countAsRefs在代码中的类型是:

{
  a: Ref<number>,
  b: Ref<number>
}

它的属性ab都是响应性的ref对象。同样的,他们也与原始count对象的属性保持同步。

根据它的特征,我们通常使用它来解构一个响应性的对象,而不会失去它的响应性。

import { reactive, toRefs } from "vue";
const count = reactive({
  a: 1,
  b: 2,
});
const { a, b } = toRefs(count);

到这里,ab都是响应性的ref对象,并且它们与原始对象的ab属性保持同步。

isRef()

从名字上看,isRef是用来判断一个值是否为ref

<script lang='ts' setup>
import { reactive,ref,isRef } from "vue"
const count = ref(1);
const countObj = reactive({
  a: 1,
})
console.log(isRef(count)); //true
console.log(isRef(countObj)); //false
</script>

unref()

实际上,它是一种语法糖。 val = isRef(val) ? val.value : val; 如果它是一个ref,它就会返回它的内部值,否则它会返回它本身。这个语法糖表明它可以删除响应性对象的反应引用。举个例子,如果我们只想获得一个响应性的值,但我们并不想让它保持响应性,我们可以使用unref来得到它的引用。例如:

<script setup lang="ts">
import { unref, ref } from "vue"
const count = ref(1)
let unRefAsCount = unref(count)
const addCount = () => {
  count.value++
}
</script>
<template>
  <div>
    {{ unRefAsCount }}
    {{ count }}
    <button @click="addCount">+1</button>
  </div>
</template>

代码中的unRefAsCount没有响应性。

shallowRef

从字面上来看,它是一个浅ref,是ref的浅层作用形式。所谓的浅ref就是与ref不同,只有.value是响应性的,而它的深层次的属性则不是响应性的。看下面的例子:

<template>
    <div>
        {{ shallowObj.a }}
        <button @click="addCount"> +1</button>
    </div>
</template>

<script lang='ts' setup>
import { shallowRef } from "vue"

const shallowObj = shallowRef({
    a: 1
})
const addCount = () => {
    //不触发页面更新
    shallowObj.value.a++
}
</script>

然而,如果我们改变addCount来修改整个.value,那么它将会触发响应性。

const addCount = () => {
  //不触发页面更新
  //shallowObj.value.a++
  let temp = shallowObj.value.a;
  temp++;
  shallowObj.value = {
    a: temp,
  };
}

triggerRef

它允许一个浅的ref在其深度属性发生改变时强制地触发变化。举个例子,就像上面的代码示例,它无法触发反应性。

<template>
    <div>
        {{ shallowObj.a }}
        <button @click="addCount"> +1</button>
    </div>
</template>

<script lang='ts' setup>
import { shallowRef, triggerRef } from "vue"

const shallowObj = shallowRef({
    a: 1
})

const addCount = () => {
    shallowObj.value.a++
    //添加'triggerRef'来强制改变。
    triggerRef(shallowObj)
}
</script>

customRef

它是一个自定义的ref,我们可以通过customRef来明确地跟踪某个值的反应性的改变。这个函数接受一个函数,这个函数以tracktrigger为参数,并且返回一个有getset方法的对象。比如,封装一个自定义反应性的对象'myRef',并控制它,使得它只在值小于5的时候触发反应性。

<template>
  <div>
    {{ count }}
    <button @click="addCount"> +1</button>
  </div>
</template>

<script lang='ts' setup>
import { customRef } from "vue"
const myRef = (value: number) => {
  const customValue = customRef((track, trigger) => {
    return {
      get() {
        //通知Vue需要跟踪后续内容的变化,这个可以自由控制。
        track()
        return value
      },
      set(newValue) {
        console.log(newValue);//myRef.value=xxx
        // 如果newValue小于5,才触发更新
        //添加一个'trigger'触发反应性,通知Vue更新页面。这里你可以自由控制是否添加'trigger'。
        if(value<5)  trigger()
        value = newValue
      }
    }
  })
  return customValue
}

const count = myRef(0)
const addCount = () => {
  count.value++
}
</script>

proxyRefs

当我们返回一个对象作为响应性引用时,对于我们想访问其属性,需要通过.value来获取。如下面的代码,state.count是无法获取属性值的,需要用state.value.count来获取,如下面的例子:

<template>
    <div>
        {{ state.value.count }}
        <button @click="addCount">+1</button>
    </div>
</template>

<script lang='ts' setup>
import { ref } from "vue"
const state = ref({
    count: 0
})
const addCount = () => {
    state.value.count++
}
</script>

为了让响应性引用的对象可以像reactive一样来访问和操作,Vue3推出了proxyRefs方法。此方法可以将响应性引用的对象代理为可直接访问/操作的响应对象,如下面的代码示例中,我们可以直接通过state.count来访问count的值:

<template>
    <div>
        {{ state.count }}
        <button @click="addCount">+1</button>
    </div>
</template>

<script lang='ts' setup>
import { ref, proxyRefs } from "vue"
const state = ref({
    count: 0
})
const stateProxy = proxyRefs(state)
const addCount = () => {
    stateProxy.count++
}
</script>

来源:Shawn King

版权声明:本文内容由TeHub注册用户自发贡献,版权归原作者所有,TeHub社区不拥有其著作权,亦不承担相应法律责任。 如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

点赞(0)
收藏(0)
Hedy
大家好!我是一位前端开发工程师,拥有6年以上的前端开发经验。我熟练掌握HTML、CSS、JavaScript等语言,能够灵活运用各种前端框架,如Vue、React、Uniapp、Flutter等。我注重理论与实践相结合,能够为学员提供丰富的案例和实践项目,并以生动、易懂的语言为学员讲解前端开发的核心知识和技能。我不仅注重传授技能,更关注学员的职业发展,希望通过我的教学,帮助学员成为一名优秀的前端开发工程师。

评论(0)

添加评论