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 函数返回的响应式对象进行解构,解构出 name 和 age 属性,并在 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>
- 运行后可以发现,当我们单击“修改 age++”按钮修改 reactive 函数返回 info 对象的 age 时,页面并没有响应式刷新。这是因为使用 ES6 解构后的数据(例如 name、age、info)不再具有响应式特性。

(3)如果想让解构出来的属性依然是响应式的,可以使用 Vue.js 3 提供的 toRets 函数。该函数会将 reactive 函数返回对象中的属性都转换成 ref 对象。这时解构出来的 name 和 age 就是 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>
- 运行可以发现,当我们单击“修改 age++”按钮修改 reactive 函数返回 info 对象的 age 时,页面会被响应式刷新。这是因为 toRets 函数返回的对象属性数据是响应式的。
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,并对其依赖项跟踪和更新触发进行控制。该函数接收一个工厂函数作为参数,该工厂函数接收 track 和 trigger 两个函数作为参数,并返回一个带有 get 和 set 方法的对象。
(2)下面我们新建一个 useDebounceRef.js 文件,通过创建自定义的 ref 来实现 debounce (防抖)操作,代码如下:
- 首先,使用 customRef 函数创建了一个自定义的 ref,即 useDebouncedRef 函数。 customRef 函数需要接收一个工厂函数,该函数接收 track 和 trigger 函数作为参数,并返回一个带有 get 和 set 函数的对象。
- 接着,在 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)