返回 导航

Vue.js

hangge.com

Vue.js 3 - Composition API使用详解4(toRefs、isRef、unref、customRef、shallowRef、triggerRef函数)

作者:hangge | 2026-04-28 08:46

四、toRefs、isRef、unref、customRef、shallowRef、triggerRef 函数

1,toRefs 函数

(1)toRefs 函数用于将一个 reactive 定义的响应式对象转换为一个普通对象。转换后的普通对象的每个属性都是指向源对象相应属性的 ref 对象。每个单独的 ref 对象都是使用 toRefs 函数创建的。

(2)例如下面样例,使用 ES6 解构语法对 reactive 函数返回的响应式对象进行解构,解构出 nameage 属性,并在 setup 函数中将其返回给模板使用。同时,还添加了一个 <button> 元素,当单击“修改 age++”按钮时对 age 进行加 1 操作。 
<template>
  <div>
    <h4>{{ name }}-{{ age }}</h4>
    <button @click="changeAge">修改age++</button>
  </div>
</template>

<script>
import { reactive, toRefs, toRef } from 'vue';

export default {
  setup() {
    const info = reactive({ name: "hangge", age: 10 });
    //  ES6语法解构reactive返回的响应式对象
    let { name, age } = info;

    const changeAge = () => {
      info.age++; // 或者 age.value++ 
      console.log(info.age)
    }

    return {
      name,
      age,
      changeAge
    }
  }
}
</script>

(3)如果想让解构出来的属性依然是响应式的,可以使用 Vue.js 3 提供的 toRets 函数。该函数会将 reactive 函数返回对象中的属性都转换成 ref 对象。这时解构出来的 nameage 就是 ref 响应式对象了。 
<template>
  <div>
    <h4>{{ name }}-{{ age }}</h4>
    <button @click="changeAge">修改age++</button>
  </div>
</template>

<script>
import { reactive, toRefs, toRef } from 'vue';

export default {
  setup() {
    const info = reactive({ name: "hangge", age: 10 });
    //toRefs 将reactive对象中的所有属性都转成ref, 建立链接
    let { name, age } = toRefs(info);

    const changeAge = () => {
      info.age++; // 或者 age.value++ 
      console.log(info.age)
    }

    return {
      name,
      age,
      changeAge
    }
  }
}
</script>

2,isRef 函数

(1)isRef 函数可以判断某个值是否为一个 ref 对象。 
(2)下面是一个简单的使用样例:
import { ref, reactive, isRef } from "vue";

const age = ref(18);
const person = reactive({ name: "Tom" });
const count = 10;

console.log(isRef(age));      // true  —— age 是 ref
console.log(isRef(person));   // false —— reactive 不是 ref
console.log(isRef(count));    // false —— 普通值不是 ref
console.log(isRef(person.name)); // false —— reactive 的属性也不是 ref

3,unref 函数

(1)unref 函数的参数如果是 ref,则返回内部值 value,否则返回参数本身。该函数是如下计算的一个语法糖:
val = isRef(val) ? val.value : val

(2)下面是一个简单的使用样例:
import { ref, unref } from "vue";

const age = ref(18);
const count = 10;

console.log(unref(age));   // 18  —— 等同于 age.value
console.log(unref(count)); // 10  —— 普通值保持原样返回

4,customRef 函数

(1)customRef 函数可以创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行控制。该函数接收一个工厂函数作为参数,该工厂函数接收 tracktrigger 两个函数作为参数,并返回一个带有 getset 方法的对象。

(2)下面我们新建一个 useDebounceRef.js 文件,通过创建自定义的 ref 来实现 debounce (防抖)操作,代码如下:
  • 首先,使用 customRef 函数创建了一个自定义的 ref,即 useDebouncedRef 函数。 customRef 函数需要接收一个工厂函数,该函数接收 tracktrigger 函数作为参数,并返回一个带有 getset 函数的对象。 
  • 接着,在 get 函数中调用 track 函数收集依赖,并返回 useDebouncedRef 函数传入的值,然后在 set 函数中实现防抖功能,并更新 value,调用 trigger 函数触发更新。 
import { customRef } from 'vue';
// 自定义ref
export default function(value, delay = 300) {
  let timer = null;
  return customRef((track, trigger) => {
    return {
      get() {
        track(); // 获取时,收集依赖
        return value;
      },
      set(newValue) {
        // 防抖的实现 
        clearTimeout(timer);
        timer = setTimeout(() => {
          value = newValue;
          trigger(); // 赋值时,触发更新
        }, delay);
      }
    }
  })
}

(3)使用时首先导入了自定义的 useDebouncedRef 函数。随后,在 setup 函数中使用该函数来提供响应式数据,并返回一个具有防抖功能的响应式对象 message,以便将其与 <inmput> 元素进行双向绑定。 
<template>
  <div>
    <input v-model="message" />
    <h4>{{ message }}</h4>
  </div>
</template>

<script>
import useDebounceRef from './useDebounceRef.js';
export default {
  setup() {
    const message = useDebounceRef("hello"); // 带有防抖功能的响应式对象
    return {
      message
    }
  }
}
</script>

(4)运行效果如下,当在 <imput> 输入框中依次输入值时, 并不会触发页面的刷新。只有当输入间隔超过 300 毫秒时,页面才会刷新。

5,shallowRef 函数

(1)shallowRef 函数可以创建一个浅层的 ref 对象。 
(2)下面是一个简单的使用样例:
import { shallowRef } from "vue";

// 创建一个浅层的ref对象
const obj = shallowRef({
  a: 1,
  b: { x: 10 }
});

// 修改obj对象的a属性不会触发响应更新
obj.value.a = 10;

// 修改深层属性 —— 不会触发响应更新
obj.value.b.x = 20;

// 替换整个对象 —— 会触发更新
obj.value = { a: 2, b: { x: 30 } };

6,triggerRef 函数

(1)triggerRef 函数可以手动强制触发依赖于一个浅层 ref 的副作用。它通常在对浅引用内部值进行深度变更后使用。 
(2)下面是一个简单的使用样例:
import { shallowRef, triggerRef, watch } from "vue";

const obj = shallowRef({ a: 1, b: 2 });

watch(obj, () => {
  console.log("触发更新!");
});

// 修改深层属性 —— 不会触发
obj.value.a = 10;

// 强制刷新
triggerRef(obj); // 打印:触发更新!
评论

全部评论(0)

回到顶部