Vue 3 的 Composition API 引入了 ref,这个简单而强大的 API 不仅仅是响应式数据的封装,还涉及到了一系列相关的概念,我们称之为 “Ref 全家桶”。本篇博客能够学习到Ref的基础知识、衍生及高级应用。
了解Ref
首先,我们从 ref 开始。它是如何帮助我们管理响应式数据的?看一下这个简单的例子:
import { ref } from 'vue';
const count = ref(0);
// 读取
console.log(count.value); // 输出:0
// 更新
count.value += 1;
console.log(count.value); // 输出:1
在这里,ref 将基本数据类型变成了一个响应式的引用,我们通过 count.value 来访问和更新值。
Ref 的衍生物
reactive:对象的响应式
当我们处理对象时,使用 reactive 可以使整个对象变得响应式:
import { reactive } from 'vue';
const user = reactive({
name: 'John',
age: 25,
});
// 读取
console.log(user.name); // 输出:John
// 更新
user.age += 1;
console.log(user.age); // 输出:26
toRef 和 toRefs:深入 Ref 的引用
如果我们只想引用对象的某个属性,可以使用 toRef 和 toRefs:
import { ref, toRef, toRefs } from 'vue';
const person = reactive({
name: 'Alice',
age: 30,
});
const nameRef = toRef(person, 'name');
console.log(nameRef.value); // 输出:Alice
// 或者一次性引用所有属性
const { name, age } = toRefs(person);
console.log(name.value, age.value); // 输出:Alice 30
customRef:定制 Ref 的行为
有时候,我们需要对 Ref 的读取和写入进行定制。这时,customRef 可以派上用场:
import { customRef } from 'vue';
function myCustomRef(initialValue) {
let value = initialValue;
return customRef((track, trigger) => ({
get() {
track(); // 依赖追踪
return value;
},
set(newValue) {
value = newValue;
trigger(); // 触发更新
},
}));
}
const customValue = myCustomRef('Hello');
console.log(customValue.value); // 输出:Hello
customValue.value = 'World';
console.log(customValue.value); // 输出:World
Ref 的高级用法
异步 Ref 更新
在异步操作中更新 Ref 时,我们可以使用 triggerRef:
import { ref, triggerRef } from 'vue';
const asyncValue = ref(0);
setTimeout(() => {
asyncValue.value += 1;
triggerRef(asyncValue); // 异步更新
}, 1000);
Ref 和生命周期钩子
Ref 和生命周期钩子密切相关,尤其是在 onMounted 和 onUnmounted 中使用 Ref:
import { ref, onMounted, onUnmounted } from 'vue';
const timer = ref(null);
onMounted(() => {
timer.value = setInterval(() => {
console.log('Timer tick!');
}, 1000);
});
onUnmounted(() => {
clearInterval(timer.value);
});
优化和性能
在使用 Ref 时,要注意避免不必要的更新。比如,可以使用 shallowRef 避免深层次的响应式
import { shallowRef } from 'vue';
const deepObject = reactive({
nested: {
prop: 'value',
},
});
const shallowObject = shallowRef(deepObject);
// shallowObject 只会追踪对象的第一层属性,避免深层次的响应式