Vue3中的自定义ref
编辑
什么是 customRef?
customRef
是一个工厂函数,接收一个工厂函数作为参数,并返回一个自定义的 Ref
对象。其类型定义如下:
function customRef<T>(factory: CustomRefFactory<T>): Ref<T>
type CustomRefFactory<T> = (
track: () => void,
trigger: () => void
) => {
get: () => T
set: (value: T) => void
}
track()
:在get
方法中调用,用于追踪依赖。trigger()
:在set
方法中调用,用于通知更新。factory
函数返回一个包含get
和set
的对象,定义如何获取和设置值。
实现一个防抖 Ref
下面是一个 Vue 官方的 customRef 应用示例:创建一个防抖 ref,即只在最近一次 set 调用后的一段固定间隔后再调用:
import { customRef } from 'vue'
export function useDebouncedRef(value, delay = 200) {
let timeout
return customRef((track, trigger) => {
return {
get() {
track()
return value
},
set(newValue) {
clearTimeout(timeout)
timeout = setTimeout(() => {
value = newValue
trigger()
}, delay)
}
}
})
}
在组件中使用:
<script setup>
import { useDebouncedRef } from './debouncedRef'
const text = useDebouncedRef('hello')
</script>
<template>
<input v-model="text" />
</template>
当用户在输入框中输入时,text
的值不会立即更新,而是在用户停止输入 200ms 后才更新并触发界面重新渲染。
其他应用场景
1. 同步到 localStorage
function useLocalStorageRef(key, defaultValue) {
return customRef((track, trigger) => {
let value = localStorage.getItem(key) ?? defaultValue;
return {
get() {
track();
return value;
},
set(newValue) {
value = newValue;
localStorage.setItem(key, newValue);
trigger();
}
};
});
}
2. 异步请求 Ref
function useAsyncRef(url) {
let value = null;
fetch(url).then(res => res.json()).then(data => {
value = data;
trigger();
});
return customRef((track, trigger) => ({
get() {
track();
return value;
},
set(newValue) {
value = newValue;
trigger();
}
}));
}
总结
customRef
提供了对依赖追踪和更新触发的细粒度控制。
适用于防抖、节流、异步操作、状态持久化等场景。
谨慎使用
当使用 customRef 时,我们应该谨慎对待其 getter 的返回值,尤其是在每次运行 getter 时都生成新对象数据类型的情况下。当这样的 customRef 作为 prop 传递时,将影响父组件和子组件之间的关系。
父组件的渲染函数可能会被其他的响应式状态变化触发。在重新渲染过程中,我们会重新评估 customRef 的值,并返回一个新的对象数据类型作为子组件的 prop。这个 prop 会与其上一个值进行比较,由于两者不同,子组件中 customRef 的响应式依赖将被触发。与此同时,因为没有调用 customRef 的 setter,父组件中的响应式依赖不会运行。
官方文档连接:
- 0
- 0
-
分享