Vue 3 自定义 ref 实战:用 customRef 封装防抖 ref 与异步 loading ref
test12026-10-210 次阅读
customRef 是什么
ref 的诞生是自动的:读写就触发依赖收集与更新。但当你想自己掌控“什么时候收集依赖、什么时候触发更新”时,就要用 customRef。它接收一个工厂函数,工厂拿到 track(收集依赖)与 trigger(触发更新)两个钩子,你决定 get 时是否 track、set 时是否立刻 trigger。
封装一个防抖 ref
输入框实时搜索时,我们不希望每次击键都更新绑定值。下面的 useDebouncedRef 在 set 时延迟一段时间才真正落值并通知视图。
import { customRef } from 'vue';
export function useDebouncedRef<T>(value: T, delay = 300) {
let timeout: ReturnType<typeof setTimeout>;
return customRef<T>((track, trigger) => ({
get() {
track();
return value;
},
set(newValue: T) {
clearTimeout(timeout);
timeout = setTimeout(() => {
value = newValue;
trigger();
}, delay);
},
}));
}
// 使用
const keyword = useDebouncedRef('', 400);
// 模板里 v-model="keyword",停手 400ms 后才更新,可拿去发请求
封装一个异步 loading ref
把“加载中”和“取值”绑在一起,调用方只关心 value 与 isLoading,不必自己维护两个 ref。
import { customRef, ref } from 'vue';
export function useAsyncRef<T>() {
const state = ref<T | null>(null);
let loading = false;
const value = customRef<T>((track, trigger) => ({
get() {
track();
return state.value as T;
},
set(v: T) {
state.value = v;
trigger();
},
}));
const load = async (promise: Promise<T>) => {
loading = true;
state.value = (await promise) as T;
loading = false;
trigger();
};
return { value, load, isLoading: () => loading };
}
注意事项
- get 里一定要调用 track,否则依赖它的组件不会重新渲染。
- set 里不调用 trigger,视图就不会更新;延迟触发时记得在定时器里调。
- customRef 适合“读写时机需要定制”的场景,普通状态用普通 ref 即可,不要过度设计。
T
test1
文章作者
customRef 是什么 ref 的诞生是自动的:读写就触发依赖收集与更新。但当你想自己掌控“什么时候收集依赖、什么时...
- 分类
- 技术
- 发布时间
- 2026-10-21
- 字数
- 约 1517 字
- 阅读
- 0 次
