今天我们聊点技术活,专门给前端的小伙伴们解解渴。最近在处理 Vue3 项目中的一个需求时,遇到了一个特别有用的 API——customRef
。
在我们的日常开发中,很多时候都会面临数据更新的困境,比如当我们有一个 computed
计算属性,它依赖于多个变量,但有些变量是非响应式的,那么这些非响应式变量发生变化时就不会触发 computed
的重新计算。
这时候该怎么办呢?别急,Vue3 给我们提供了一个强大的工具,帮助我们随心所欲地控制数据更新,这就是 customRef。
简单来说,我们有一个 computed
计算属性 sum
,它依赖于一些响应式变量,也依赖于一些非响应式变量。
在 Vue 中,当响应式变量发生变化时,computed
会自动更新,但是如果是非响应式变量发生变化,computed
就不会触发更新。
举个例子,如果 sum
的计算依赖了变量 count1
和 count2
,而 count1
是响应式的,count2
是普通变量,那么当 count2
改变时,sum
并不会更新。为了解决这个问题,我们可以使用 Vue3 的 customRef
。
customRef
是 Vue3 提供的一个强大的 API,它允许我们创建一个自定义的 ref,从而显式地声明对其依赖追踪和更新触发的控制方式。简单来说,customRef
给了我们更多的控制权,让我们能精确地控制数据的更新时机。
customRef()
接受一个工厂函数,这个函数有两个参数:track
和 trigger
。这两个函数分别用来追踪依赖和触发更新。track()
通常在 get()
方法中调用,trigger()
则在 set()
中调用。通过这种方式,我们可以精确地控制什么时候进行依赖追踪,什么时候触发更新。
创建一个防抖 ref
我们可以通过 customRef
实现一些自定义的行为,比如创建一个防抖的 ref
,即只有在 set
被调用后一段固定时间后才触发更新。这种用法在一些高频更新的场景中非常有用,比如搜索框输入时防止每次输入都触发请求。
import { customRef } from 'vue';
function useDebouncedRef(initialValue, delay) {
let timeout;
return customRef((track, trigger) => {
return {
get() {
track(); // 追踪依赖
return initialValue;
},
set(value) {
clearTimeout(timeout);
timeout = setTimeout(() => {
initialValue = value;
trigger(); // 延迟触发更新
}, delay);
}
};
});
}
在这个例子中,useDebouncedRef
创建了一个防抖的 ref。当我们为 ref
设置一个新值时,set()
方法会清除之前的定时器,并设置一个新的定时器来在指定的 delay
后更新 ref
的值。这样就能有效地防止频繁触发更新。
可控的 computed
回到我们刚才的需求,我们需要一个“可控的 computed”。这意味着我们希望能够手动触发 computed
的更新,特别是在一些非响应式变量变化时,computed
的值也能重新计算。
为了实现这一点,我们依然可以使用 customRef
来创建一个带有自定义更新逻辑的 computed
。
假设我们有如下的需求:sum
依赖于 count1
(响应式)和 count2
(非响应式),当 count2
变化时,我们希望 sum
能够手动触发更新。我们可以这样实现:
import { reactive, computed, customRef } from 'vue';
function useManualComputed(deps, computeFn) {
let value;
let dirty = true;
const ref = customRef((track, trigger) => {
return {
get() {
if (dirty) {
track(); // 追踪依赖
value = computeFn();
dirty = false;
}
return value;
},
set() {
dirty = true; // 手动设置为脏数据,强制重新计算
trigger();
}
};
});
// 返回 ref 和手动更新的方法
return [ref, () => { dirty = true; }];
}
// 使用方式
const count1 = reactive({ value: 0 });
let count2 = 10;
const sumFn = () => count1.value + count2;
const [sum, refreshSum] = useManualComputed([count1, count2], sumFn);
console.log(sum.value); // 0
// 修改 count2,不会自动触发 sum 的更新
count2 = 20;
refreshSum(); // 手动触发更新
console.log(sum.value); // 20
在这个例子中,useManualComputed
返回一个包含 computed
值的 ref
和一个手动触发更新的函数 refreshSum
。当 count2
改变时,我们可以调用 refreshSum
来手动触发 sum
的更新。
customRef
这个 API 在 Vue3 中为我们提供了更多的控制权,尤其是在面对复杂的数据更新逻辑时。通过 customRef
,我们可以创建带有自定义行为的响应式数据,不仅能够精确控制依赖追踪,还能灵活地触发更新。
如果你在项目中遇到了类似的需求,比如需要在非响应式变量变化时手动触发 computed
更新,customRef
绝对是一个值得一试的好工具。
通过它,我们不仅能解决这些问题,还能在很多场景中实现更高效的数据更新机制。希望这篇文章能帮助到大家,让你们在开发中更加得心应手。
目前,对编程、职场感兴趣的同学,大家可以联系我微信:golang404,拉你进入“程序员交流群”。
虎哥私藏精品 热门推荐 虎哥作为一名老码农,整理了全网最全《前端资料合集》。